Генерация картинок ruDALL-E. Мануал по созданию TS парсера

Генерация картинок ruDALL-E. Мануал по созданию TS парсера

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

2022-02-07-12-47-26.png



Определяем задачу и действия

В самом начале нужно понять алгоритм действий для получения изображения. После нескольких генераций на сайте вручную, можно понять последовательность действий:
1. Переходим на страницу https://rudalle.ru/demo и получаем картинку с капчей
2. Разгадываем капчу
3. Отправляем текст по которому будет сгенерирована картинка и ответ капчи.
2022-02-07-12-39-46.png

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']]
];

После чего вот так можно будет выбрать эту опцию в парсере:
2022-02-07-13-21-11.png



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);
Если же проверка пройдена и данные введены верно, тогда записываем данные в объект gen который можно инициализировать где-то выше

Дополнительно если капчу разгадали неверно, тогда нужно сделать вторую попытку и для это можно сделать обёртку в цикле и записать это в новый метод:

Код:
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

2022-02-07-17-39-02.png
Автор
Support Ilia
Просмотры
134
Первый выпуск
Обновление

Рейтинги

5,00 звёзд Оценок: 2

Ещё ресурсы от Support Ilia

Последние отзывы

крутая штуковина
Назад
Верх