В данный момент А-Парсер предоставляет широкие возможности для написания собственного парсера имея небольшие знания программирования и JavaScript. А-Парсер позволяет сосредоточится именно на написании логики; работу с многопоточностью, сетью, прокси, результатами, логами и т.д. A-Parser берет на себя. Код можно писать прямо в интерфейсе парсера, добавив новый парсер в Редакторе парсеров. Также для написания парсеров можно использовать сторонние редакторы, например VSCode
- Минимальная версия A-Parser:
- 1.2.1435
В данной статье описано создание TypeScript парсера, отправка GET и POST запросов (чтобы не путать GET/POST запрос с запросом который подаётся на вход парсеру, далее будем называть реквест от анг. request), нахождение капчи на странице с отправкой на разгадывание в сервис и получением результата
В качестве целевого сайта выступает сервис нейросеть ruDALL-E что позволяет генерировать изображения по тексту. Для успешной генерации нужно решить капчу и подождать время для генерации
Готовый пресет можно скачать тут: Генерация картинок ruDALL-E
Определяем задачу и действия
В самом начале нужно понять алгоритм действий для получения изображения. После нескольких генераций на сайте вручную, можно понять последовательность действий:
1. Переходим на страницу https://rudalle.ru/demo и получаем картинку с капчей
2. Разгадываем капчу
3. Отправляем текст по которому будет сгенерирована картинка и ответ капчи.
4. Получаем страницу с временем ожидания
5. После ожидания получаем страницу с сгенерированной картинкой, и парсим ссылку на неё
6. По ссылке скачиваем картинку в нужную нам папку
После получения понимания алгоритма нужно просмотреть каждый запрос в браузере, какие заголовки, метод, данные отправляются по реквесту. И просто повторить эти действия в коде. В данном случае все реквесты идут по цепочке и чтобы выполнить следующий реквест, нужны данные в ответе предыдущего (такое часто встречается в парсинге)
Таким образом определили что в качестве запроса парсеру будет строка текста по которой будет произведена генерация картинки.
Также новому парсеру нужно добавить опцию выбора пресета для разгадывания капч:
this.conf.Util_AntiGate_preset - это настройка в конфиге, хранит название выбранного пресета для Util::AntiGate
Чтобы добавить нужно прописать значение будущей опции в конфиг в
static defaultConf: typeof BaseParser.defaultConf
Код:Util_AntiGate_preset: 'default'
и добавить комбобокс для выбора в интерфейсе
После чего вот так можно будет выбрать эту опцию в парсере:Код:static editableConf: typeof BaseParser.editableConf = [ ['Util_AntiGate_preset', ['combobox', 'Util::AntiGate preset']] ];
1. Переходим на страницу https://rudalle.ru/demo и получаем картинку с капчей
csrfmiddlewaretoken и captcha_0 - это специальные идентификаторы капчи, нужны для отправки результата капчиКод:let csrfmiddlewaretoken, captcha_0, captchaImageLink, resp = await this.request('GET', 'https://rudalle.ru/demo', {}, { decode: 'auto-html', headers: { 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' }, check_content: [(data) => { try { csrfmiddlewaretoken = data.match(/name="csrfmiddlewaretoken" value="(.*?)"/)[1]; captcha_0 = data.match(/name="captcha_0" value="(.*?)"/)[1]; captchaImageLink = 'https://rudalle.ru' + data.match(/<img src="(\/captcha\/image\/.*?\/)" alt="captcha" class="captcha"/)[1]; return true; } catch (e) { return false; } }] });
captchaImageLink - это ссылка на картинку с капчей и нужна чтобы отправить сервису на разгадывание
Как видно данные собираем обычными регулярками
2. Разгадываем капчу
Используем раннее полученную ссылку на изображение капчи и выполняем отправку её в сервис разгадывания с помощью метода А-Парсера
await this.captcha.recognizeFromUrl(preset, url[, overrides]):
Код:let captchaResponse = await this.captcha.recognizeFromUrl(this.conf.Util_AntiGate_preset, captchaImageLink); if(!captchaResponse.answer) { this.logger.put('Ошибка в разгадывании капчи'); } this.logger.put(captchaResponse.answer); if(captchaResponse.answer) { // тут будет следующая логика: отправка текста по которому будет сгенерирована картинка и ответ капчи }
3. Отправляем текст по которому будет сгенерирована картинка и ответ капчи
Для это нужно выполнить реквест который ранее обнаружили в браузере и повторили в коде, только с заменой нужных данных
После реквеста видно проверку на правильность введённых данных. Неправильно можно было ввести капчу, когда сервис в ответе прислал не верное решения капчи. Тогда нужно сообщить сервису который разгадал капчу, что капча была разгадана неверно:Код:if(captchaResponse.answer) { const {success, data} = await this.request('POST', 'https://rudalle.ru/generate_image', { csrfmiddlewaretoken, text: query, // тут в query содержится set.query - текст по которому будет сгенерировано изображение captcha_0, captcha_1: captchaResponse.answer, // отправляем разгаданную капчу }, { decode: 'auto-html', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } }); if(success && typeof data == 'string') { if(/>Вы ввели что-то не то в форму или неправильно заполнили каптчу.</i.test(data)) { this.logger.put('Вы ввели что-то не то или неправильно заполнили каптчу. Нужно попробовать снова'); await this.captcha.reportBad(this.conf.Util_AntiGate_preset, captchaResponse.id); } else { gen.success = success; gen.data = data; } } }
Если же проверка пройдена и данные введены верно, тогда записываем данные в объект gen который можно инициализировать где-то вышеКод:await this.captcha.reportBad(this.conf.Util_AntiGate_preset, captchaResponse.id);
Дополнительно если капчу разгадали неверно, тогда нужно сделать вторую попытку и для это можно сделать обёртку в цикле и записать это в новый метод:
Такой метод вернёт страницу которая говорит об успешном начале генерации и примерном времени ожиданияКод:async startGeneration(query) { let gen = { success: 0, data: '' }; for (let attempt = 1; attempt <= this.conf.proxyretries; ++attempt) { let csrfmiddlewaretoken, captcha_0, captchaImageLink, resp = await this.request('GET', 'https://rudalle.ru/demo', {}, { decode: 'auto-html', attempt, headers: { 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' }, check_content: [(data) => { try { csrfmiddlewaretoken = data.match(/name="csrfmiddlewaretoken" value="(.*?)"/)[1]; captcha_0 = data.match(/name="captcha_0" value="(.*?)"/)[1]; captchaImageLink = 'https://rudalle.ru' + data.match(/<img src="(\/captcha\/image\/.*?\/)" alt="captcha" class="captcha"/)[1]; return true; } catch (e) { return false; } }] }); let captchaResponse = await this.captcha.recognizeFromUrl(this.conf.Util_AntiGate_preset, captchaImageLink); if(!captchaResponse.answer) { this.logger.put('Ошибка в разгадывании капчи'); continue; } this.logger.put(captchaResponse.answer); if(captchaResponse.answer) { const {success, data} = await this.request('POST', 'https://rudalle.ru/generate_image', { csrfmiddlewaretoken, text: query, captcha_0, captcha_1: captchaResponse.answer, }, { decode: 'auto-html', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } }); if(success && typeof data == 'string') { if(/>Вы ввели что-то не то в форму или неправильно заполнили каптчу.</i.test(data)) { this.logger.put('Вы ввели что-то не то или неправильно заполнили каптчу. Нужно попробовать снова'); await this.captcha.reportBad(this.conf.Util_AntiGate_preset, captchaResponse.id); continue; } else { gen.success = success; gen.data = data; return gen; } } } } return gen; }
4. Получаем страницу с временем ожидания
По сути эта страница уже получена предыдущим шагом. Т.к. когда был отправлен реквест с ответом капчи, тогда и произошёл редирект на страницу с временем ожидания. И осталось только распарить её, получить полезные данные перед следующим шагом
Минуты ожидания и ссылку по которой можно получить страницу с сгенерированной картинкой:
После получения количества минут, прописываем задержку в потоке на 20 секунд с помощью метода await this.sleep(sec). Таким образом парсер будет проверять через каждые 20 секунд в течении 10 минут готовность изображения к скачиванию. В случае когда сайт говорит что будет готово через 2 минуты, но фактически изображение может быть готово уже через минуту, это ускорит парсинг в целомКод:let minutes; let checkImageUrl; if (/estimationTime = \+"\d+";/.test(data)) { minutes = parseInt(data.match(/estimationTime = \+"(\d+)";/)[1]); } if (/url = "https:\/\/rudalle.ru\/check_image\/.+?";/.test(data)) { checkImageUrl = data.match(/url = "(https:\/\/rudalle.ru\/check_image\/.+?)";/)[1] } if (minutes && checkImageUrl) { this.logger.put(`Генерация началась. Примерное время ожидания: ${minutes} мин.`); for (let time = 20; time <= 600; time+=20) { await this.sleep(20); //тут будет следующий шаг и его реквест } } else { this.logger.put('Не удалось получить ссылку на проверку готовности изображения'); }
5. После ожидания получаем страницу с сгенерированной картинкой, и парсим ссылку на неё
Получаем страницу и парсим с неё ссылку на сгенерированное изображение
Код:const {success, data} = await this.request('GET', checkImageUrl, {}, { decode: 'auto-html', headers: { 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } }); if(success && typeof data == 'string') { let imageUrl if (/<img src="https:\/\/img.rudalle.ru\/images\/[^"]+"\s*class="cardimage"/.test(data)) { imageUrl = data.match(/<img src="(https:\/\/img.rudalle.ru\/images\/[^"]+)"\s*class="cardimage"/)[1]; // тут следующий шаг по скачиванию изображения await this.saveImage(imageUrl); break; } else { this.logger.put('Не удалось получить ссылку на картинку'); } }
6. По ссылке скачиваем картинку в нужную нам папку
Метод который скачивает изображение по ссылке. Знаем что ссылка на изображение может иметь несколько слэшей, текст между слэшами и заканчивается на уникальный идентификатор картинки и расширение. Берём уникальный идентификатор картинки и расширение (по сути всё что после последнего слэша) за название изображения при скачивании
После этого сгенерированные изображения сохраняются в папку aparser\results\imagesКод:async saveImage(url) { let reverseStr = [...url].reverse().join(""); reverseStr = reverseStr.match(/([^\/]+)/)[1]; let file = [...reverseStr].reverse().join(""); const {success} = await this.request('GET', url, {}, { save_to_file: 'results/images/' + file }); if(success) this.logger.put('Картинка сохранена успешно'); else this.logger.put('Не удалось сохранить картинку'); }
-
Вступайте в наш Telegram чат: https://t.me/a_parser Нас уже 2600+ и мы растем!Скрыть объявление
Генерация картинок ruDALL-E. Мануал по созданию TS парсера
Позволяет генерировать изображения по тексту
Метки: