- English Name
- Image generation ruDALL-E. Manual for creating a TS scraper
- Минимальная версия A-Parser
- 1.2.1435
В данный момент А-Парсер предоставляет широкие возможности для написания собственного парсера имея небольшие знания программирования и JavaScript. А-Парсер позволяет сосредоточится именно на написании логики; работу с многопоточностью, сетью, прокси, результатами, логами и т.д. A-Parser берет на себя. Код можно писать прямо в интерфейсе парсера, добавив новый парсер в Редакторе парсеров. Также для написания парсеров можно использовать сторонние редакторы, например VSCode
В данной статье описано создание 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
и добавить комбобокс для выбора в интерфейсе
После чего вот так можно будет выбрать эту опцию в парсере:
1. Переходим на страницу https://rudalle.ru/demo и получаем картинку с капчей
csrfmiddlewaretoken и captcha_0 - это специальные идентификаторы капчи, нужны для отправки результата капчи
captchaImageLink - это ссылка на картинку с капчей и нужна чтобы отправить сервису на разгадывание
Как видно данные собираем обычными регулярками
2. Разгадываем капчу
Используем раннее полученную ссылку на изображение капчи и выполняем отправку её в сервис разгадывания с помощью метода А-Парсера
await this.captcha.recognizeFromUrl(preset, url[, overrides]):
3. Отправляем текст по которому будет сгенерирована картинка и ответ капчи
Для это нужно выполнить реквест который ранее обнаружили в браузере и повторили в коде, только с заменой нужных данных
После реквеста видно проверку на правильность введённых данных. Неправильно можно было ввести капчу, когда сервис в ответе прислал не верное решения капчи. Тогда нужно сообщить сервису который разгадал капчу, что капча была разгадана неверно:
Если же проверка пройдена и данные введены верно, тогда записываем данные в объект gen который можно инициализировать где-то выше
Дополнительно если капчу разгадали неверно, тогда нужно сделать вторую попытку и для это можно сделать обёртку в цикле и записать это в новый метод:
Такой метод вернёт страницу которая говорит об успешном начале генерации и примерном времени ожидания
4. Получаем страницу с временем ожидания
По сути эта страница уже получена предыдущим шагом. Т.к. когда был отправлен реквест с ответом капчи, тогда и произошёл редирект на страницу с временем ожидания. И осталось только распарить её, получить полезные данные перед следующим шагом
Минуты ожидания и ссылку по которой можно получить страницу с сгенерированной картинкой:
После получения количества минут, прописываем задержку в потоке на 20 секунд с помощью метода await this.sleep(sec). Таким образом парсер будет проверять через каждые 20 секунд в течении 10 минут готовность изображения к скачиванию. В случае когда сайт говорит что будет готово через 2 минуты, но фактически изображение может быть готово уже через минуту, это ускорит парсинг в целом
5. После ожидания получаем страницу с сгенерированной картинкой, и парсим ссылку на неё
Получаем страницу и парсим с неё ссылку на сгенерированное изображение
6. По ссылке скачиваем картинку в нужную нам папку
Метод который скачивает изображение по ссылке. Знаем что ссылка на изображение может иметь несколько слэшей, текст между слэшами и заканчивается на уникальный идентификатор картинки и расширение. Берём уникальный идентификатор картинки и расширение (по сути всё что после последнего слэша) за название изображения при скачивании
После этого сгенерированные изображения сохраняются в папку aparser\results\images
В данной статье описано создание 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 и получаем картинку с капчей
Код:
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;
}
}]
});
csrfmiddlewaretoken и captcha_0 - это специальные идентификаторы капчи, нужны для отправки результата капчи
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;
}
}
}
После реквеста видно проверку на правильность введённых данных. Неправильно можно было ввести капчу, когда сервис в ответе прислал не верное решения капчи. Тогда нужно сообщить сервису который разгадал капчу, что капча была разгадана неверно:
Код:
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. Получаем страницу с временем ожидания
По сути эта страница уже получена предыдущим шагом. Т.к. когда был отправлен реквест с ответом капчи, тогда и произошёл редирект на страницу с временем ожидания. И осталось только распарить её, получить полезные данные перед следующим шагом
Минуты ожидания и ссылку по которой можно получить страницу с сгенерированной картинкой:
Код:
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('Не удалось получить ссылку на проверку готовности изображения');
}
После получения количества минут, прописываем задержку в потоке на 20 секунд с помощью метода await this.sleep(sec). Таким образом парсер будет проверять через каждые 20 секунд в течении 10 минут готовность изображения к скачиванию. В случае когда сайт говорит что будет готово через 2 минуты, но фактически изображение может быть готово уже через минуту, это ускорит парсинг в целом
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. По ссылке скачиваем картинку в нужную нам папку
Метод который скачивает изображение по ссылке. Знаем что ссылка на изображение может иметь несколько слэшей, текст между слэшами и заканчивается на уникальный идентификатор картинки и расширение. Берём уникальный идентификатор картинки и расширение (по сути всё что после последнего слэша) за название изображения при скачивании
Код:
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('Не удалось сохранить картинку');
}
После этого сгенерированные изображения сохраняются в папку aparser\results\images