Добрый день. Подскажите, пожалуйста. Как я понял, данный формат результата содержит искомые данные на сайте, так как регулярок в пресете я не вижу. Как понять, что это за переменные (text, texts) и за что они отвечают, откуда берутся, что содержат и тд? Мне нужно сделать похожий парсинг, только парсить не статьи, а конкретные данные. Как я могу их задать?
Добрый день Если навести курсором мыши на название парсера HTML::TextExtractor, то вы увидите все переменные которые содержат результаты и там есть $p1.texts.$i.text, где texts это наименования массива, а text - это имя переменной в которой содержится один текст, а в texts содержится множество text Далее, если рассматривать конкретно этот формат результата, то тут используется только переменная texts которая содержит множество текстов. Конструкция FOREACH позволяет нам создать логику прохождения по этому множеству и что-то сделать с каждым текстом Так как это стандартные результаты, то их задать нельзя, только вывести или обработать, например в конструкторе результатов идёт обработка удаления тегов Remove HTML tags но массив(множество) texts просто перезаписывается, хотя можно было бы складывать в новый массив под новым именем, и уже его тогда нужно было бы выводить в формате результата Чтобы парсить конкретные данные, то проще создать регулярку и сохранять в новые переменные. Вот тут описано это детально с примерами: https://a-parser.com/docs/guides/task-settings/using-regular-expressions
Подскажите, что не так делаю. Импорт выполнил, и без изменений добавил задание. Но оно не выполнилось, и вот лог: Thread #1 21/08 17:50:21 - 21/08 17:51:22 HTML::TextExtractor::0(Complete): https://a-parser.com/ 21/08 17:50:21 Parser HTML::TextExtractor::0 parse query https://a-parser.com/ 21/08 17:50:21 Use proxy http://5.252.161.48:3128 21/08 17:50:22 GET(1): https://a-parser.com/ - 596 HTTPS(C) proxy error: 400 Bad Request (0 KB) 21/08 17:50:22 Parse response: 3 21/08 17:50:22 Ban proxy 5.252.161.48:3128 for parser HTML::TextExtractor for 300 seconds 21/08 17:50:22 Use proxy socks5://184.178.172.5:15303 21/08 17:51:21 GET(2): https://a-parser.com/ - 200 OK (truncated by max_size) (1054.16 KB) 21/08 17:51:21 Decode from utf-8(meta charset) 21/08 17:51:21 Parse response: 1 21/08 17:51:21 Thread complete work
вроде всё верно делаешь. судя по логу - всё выполнилось, но на сайте апарсера нет нужных по размеру статей.
В формате результата измените значение с 1000 на 100 и запустите еще раз. Будут найдены текстовые блоки > 100 символов. Просто текстовых блоков более 1000 символов на сайте найдено не было.
Добрый день Если список ссылок собран в большое количество файлов, разложеннывх по подпапкам, есть ли способ в одном задании перебрать все эти файлы? При выборе папки через обычный диалог "Выберите файл" в разделе "Запросы" в текстовое поле сразу подгружаются имена всех файлов в папке. Если их сотни тысяч, то все просто зависает.
Через интерфейс это единственный способ. Можно то же самое сделать через API. Но, обратите внимание, на каждый файл будет создано отдельное задание. Если подпапок/файлов очень много, то конечно парсеру нужно будет время, чтобы перечитать их все.
Понял, а если я вручную свормирую список всех файлов, можно ли его для HTML::TextExtractor указать списком, как в этом примере https://a-parser.com/resources/338/ ?
Можно только если написать аналогичную обертку для HTML::TextExtractor реализующую чтение файлов по путям, указанным в поле запросов.
попробовал пор образцу https://a-parser.com/resources/420/ сделать аналогичный парсер с HTML::ArticleExtractor Спойлер: мой код Код: const fs = require('fs'); const readline = require('readline'); class Parser { constructor() { this.defaultConf = { version: '0.1.24', results: { flat: [ ['Content', 'Content'], ] }, results_format: '$p1.textContent.collapse', ArticleExtractor_preset: 'default' }; this.editableConf = [ ['ArticleExtractor_preset', ['combobox', 'HTML::ArticleExtractor preset']], ]; } *parse(set, results) { if (set.lvl === 0) { results.SKIP = 1; results.success = 1; const files = fs.readdirSync(set.query); this.logger.put(`Found ${files.length} files`); for (let filename of files) { this.query.add({ query: `${set.query}/${filename}`, filename }); } } else { try { var fileStream = fs.createReadStream(set.filename); var lineReader = readline.createInterface({ input: fileStream, crlfDelay: Infinity }); this.logger.put(`Current file ${set.filename} `); lineReader.on('curr_url', function (curr_url) { this.logger.put(`Current URL ${curr_url}`); let resp = yield this.parser.request('HTML::ArticleExtractor', this.conf.ArticleExtractor_preset, {}, curr_url); if(resp.info.success) results.Content = resp.textContent.collapse; results.success = resp.info.success; }); } catch(e) { this.logger.put(`Error: ${e.message}`); results.success = 0; } } return results; } } но получаю ошибку Error: Start: JS::FilesFromDirText Error: files/parsers/FilesFromDirText/FilesFromDirText.js:45 let resp = yield this.parser.request('HTML::ArticleExtractor', this.conf.ArticleExtractor_preset, {}, curr_url); ^^^^^ SyntaxError: Unexpected strict mode reserved word at new Script (node:vm:99:7) at createScript (node:vm:260:10) at Object.runInContext (node:vm:291:10) at evalmachine.:1:16930 at __requireParserAsModule (evalmachine.:1:11521) at __prepareParserClass (evalmachine.:1:11941) at unknown:1:1 at Script.runInContext (node:vm:141:12) at Object.runInContext (node:vm:292:6) at evalmachine.:1:16930 at build/core.to_build.pl line 63587. я упустил что-то важное?
Нужно использовать async генератор и читать строки используя await. А также, лучше немного изменить логику работы, добавив еще один уровень запросов: 0) Читаем список файлов из каталога 1) Читаем список ссылок из каждого файла 2) Парсим данные по каждой ссылке Вот рабочее решение: Код: const fs = require('fs'); const readline = require('readline'); class Parser { constructor() { this.defaultConf = { results: { flat: [ ['Content', 'Content'] ] }, results_format: '[% Content.collapse %]', HTML_ArticleExtractor_preset: 'default' }; this.editableConf = [ ['HTML_ArticleExtractor_preset', ['combobox', 'HTML::ArticleExtractor preset']] ]; } async *parse(set, results) { if(set.lvl == 0) { this.logger.put(`Read directory ${set.query}`); const files = fs.readdirSync(set.query); for (let filename of files) { this.query.add(`${set.query}\\${filename}`); } this.logger.put(`Found ${files.length} files`); results.SKIP = 1; results.success = 1; } else if(set.lvl == 1) { try { this.logger.put(`Read file ${set.query}`); let fileStream = fs.createReadStream(set.query); let lineReader = readline.createInterface({ input: fileStream, crlfDelay: Infinity }); let count = 0; for await (const url of lineReader) { this.query.add(url); count++; } this.logger.put(`Found ${count} urls`); results.success = 1; } catch(e) { this.logger.put(`Error: ${e.message}`); results.success = 0; } results.SKIP = 1; } else { let resp = yield this.parser.request('HTML::ArticleExtractor', this.conf.HTML_ArticleExtractor_preset, {}, set.query); results.success = resp.info.success; if(resp.info.success) results.Content = resp.textContent; } return results; } }