Михаил Сисин Со-основатель облачного сервиса по сбору информации и парсингу сайтов Diggernaut. Работает в области сбора и анализа данных, а также разработки систем искусственного интеллекта и машинного обучения  более десяти лет.

Решаем Google ReCaptcha v3: сервис RuCaptcha интегрирован в платформу Diggernaut

Решаем Google ReCaptcha v3: сервис RuCaptcha интегрирован в платформу Diggernaut

В рядах поддерживаемых нами сервисов для решения капчи пополнение. Встречайте сервис RuCaptcha.

Функционал сервиса схож с AntiCaptcha, позволяет решать все основные типы капч, а также поддерживает режим “proxyless”, что весьма востребованно нашими пользователями. Цены на услуги у RuCaptcha ниже чем у сравнимого с ним сервиса AntiCaptcha. Но от всех остальных провайдеров, сервис RuCaptcha отличает то, что они предлагают решение для Google ReCaptcha v3. Мы его протестировали и оно действительно работает.

Более детальная информация об использовании сервиса по решению капч в вашем парсере доступна в нашей документации.

А ниже мы расскажем как использовать RuCaptcha для решения Google ReCaptcha v3 на примере сайта ГИБДД. А запрашивать мы будем информацию о регистрациях в ГИБДД по VIN номеру.

Для начала, зайдем на сайт ГИБДД и удостоверимся, что на странице с формой для поиска используется ReCaptcha v3. На первый взгляд, в исходном коде страницы не наблюдается линк на api.js от Google, поэтому автоматическое извлечение ключа сайта и параметра action работать не будет и нам надо найти их вручную. Если мы посмотрим во вкладку Сеть в консоли разработчика вашего браузера (Chrome/Firefox), то мы увидим что api.js все же подгружается, а значит подгрузка осуществляется не напрямую, а используя какой-то javascript. Поэтому нашей задачей будет отсмотреть все подгруженные JS файлы во вкладке Сеть.

Ищем параметры для recaptcha v3

Просматривая код JS файлов, мы увидим что в коде JS файла app.js есть интересный блок в конце:

/* reCaptcha */
var reCaptchaSiteKey = '6Lc66nwUAAAAANZvAnT-OK4f4D_xkdzw5MLtAYFL';
var onloadReCaptcha = function() {
    grecaptcha.execute(reCaptchaSiteKey, {action: 'check_auto'})
    .then(function(token) {
        appVehicleCheck.reCaptchaToken = token;
    });
}

Отсюда мы забираем ключ сайта (6Lc66nwUAAAAANZvAnT-OK4f4D_xkdzw5MLtAYFL) и параметр action (check_auto).

Далее нам надо определить какой запрос делает страница, когда мы нажимаем кнопку поиска. Для этого открываем панель разработчика в браузера, переходим во вкладку Сеть и ставим фильтр, чтобы нам показывались только XHR запросы.

Делаем запрос в ГИБДД

Мы увидим, что загружается следующий ресурс: https://xn--b1afk4ade.xn--90adear.xn--p1ai/proxy/check/auto/history методом POST и туда передается VIN, тип проверки и токен Google ReCaptcha v3.

Получаем ответ из ГИБДД

Таким образом, у нас есть все, чтобы написать парсер. ВНИМАНИЕ – парсер требует наличие русского прокси, доступ до данных для иностранных IP заблокирован:

---
config:
    debug: 2
    agent: "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
        proxy: ПОМЕСТИТЕ ВАШ ПРОКСИ СЮДА В ФОРМАТЕ 1.1.1.1:9999 (ИЛИ USER:PASS@1.1.1.1:9999 ПРИ ОРГАНИЗАЦИИ ДОСТУПА К ПРОКСИ ПО ПАРОЛЮ)
do:
# ПРЕДУСТАНАВЛИВАЕМ ПРОВЕРЯЕМЫЙ VIN В ПЕРЕМЕННУЮ
- variable_set:
    field: vin
    value: WVGZZZ7LZ8D050320
# ЗАГРУЖАЕМ СТРАНИЦУ С ФОРМОЙ ПОИСКА
- walk:
    to: https://xn--90adear.xn--p1ai/check/auto/
    do:
    # РЕШАЕМ КАПЧУ
    - captcha_resolve:
        provider: rucaptcha
        type: recaptchav3
        apikey: ЗДЕСЬ ДОЛЖЕН БЫТЬ ВАШ RUCAPTCHA АПИ КЛЮЧ 
        sitekey: 6Lc66nwUAAAAANZvAnT-OK4f4D_xkdzw5MLtAYFL
        minscore: 0.3
        action: check_auto
    # ЗАХОДИМ В БЛОК BODY НА СТРАНИЦЕ, ТАК КАК НАМ НУЖНО ПЕРЕЙТИ В БЛОКОВЫЙ КОНТЕКСТ
    - find:
        path: body
        do:
        # ЧИТАЕМ СОДЕРЖИМОЕ ПЕРЕМЕННОЙ captcha В РЕГИСТР (ИМЕЕНО В НЕЙ ДОЛЖЕН БУДЕТ НАХОДИТЬСЯ ТОКЕН)
        - variable_get: captcha
        # ПРОВЕРЯЕМ ЕСТЬ ЛИ У НАС ТОКЕН
        - if:
            match: \S
            do:
            # ДЕЛАЕМ POST ЗАПРОС ДЛЯ ЗАБОРА ГЕРИСТРАЦИОННЫХ ДАННЫХ
            - walk:
                to:
                    post: https://xn--b1afk4ade.xn--90adear.xn--p1ai/proxy/check/auto/history
                    data:
                        vin: <%vin%>
                        captchaWord: ''
                        checkType: history
                        reCaptchaToken: <%captcha%>
                do:
                # ПАРСИМ ДАННЫЕ И СКЛАДЫВАЕМ В ОБЪЕКТ
                - find:
                    path: requestresult
                    do:
                    - object_new: vehicle
                    - find:
                        path: vehicle>enginevolume
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: engine_volume
                    - find:
                        path: vehicle>color
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: color
                    - find:
                        path: vehicle>bodynymber
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: body_number
                    - find:
                        path: vehicle>year
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: year
                    - find:
                        path: vehicle>enginenumber
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: engine_number
                    - find:
                        path: vehicle>vin
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: vin
                    - find:
                        path: vehicle>model
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: model
                    - find:
                        path: vehicle>category
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: category
                    - find:
                        path: vehicle>type
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: type
                    - find:
                        path: vehicle>powerhp
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: power_hp
                    - find:
                        path: vehicle>powerkwt
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: power_kwt
                    - find:
                        path: vehiclepassport>number
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: passport_number
                    - find:
                        path: vehiclepassport>issue
                        do:
                        - parse
                        - object_field_set:
                            object: vehicle
                            field: passport_issued
                    - find:
                        path: ownershipperiod
                        do:
                        - object_new: ownership
                        - find:
                            path: from
                            do:
                            - parse
                            - object_field_set:
                                object: ownership
                                field: from
                        - find:
                            path: to
                            do:
                            - parse
                            - object_field_set:
                                object: ownership
                                field: to
                        - find:
                            path: simplepersontype
                            do:
                            - parse
                            - object_field_set:
                                object: ownership
                                field: owner_type
                        - find:
                            path: lastoperation
                            do:
                            - parse
                            - object_field_set:
                                object: ownership
                                field: operation_type
                        - object_save:
                            name: ownership
                            to: vehicle
                    - object_save:
                        name: vehicle

Если мы запустим его на платформе Diggernaut (естественно, вы должны будете использовать ваш API ключ в сервисе RuCaptcha в коде парсера), то мы получим следующий датасет (приводим пример выгрузки датасета в формате JSON):

[{
    "vehicle": {
        "category": "В",
        "color": "ЧЕРНЫЙ",
        "engine_number": "080571",
        "engine_volume": "2967.0",
        "model": "ФОЛЬКСВАГЕН ТОUАRЕG",
        "ownership": [
            {
                "from": "2008-05-22T00:00:00.000+04:00",
                "operation_type": "11",
                "owner_type": "Natural",
                "to": "2011-12-10T00:00:00.000+04:00"
            },
            {
                "from": "2011-12-10T00:00:00.000+04:00",
                "operation_type": "06",
                "owner_type": "Natural",
                "to": "2017-02-02T00:00:00.000+03:00"
            },
            {
                "from": "2017-02-02T00:00:00.000+03:00",
                "operation_type": "03",
                "owner_type": "Natural"
            }
        ],
        "passport_issued": "ТАМОЖНЯ: 10009191",
        "passport_number": "78ТУ623619",
        "power_hp": "224",
        "power_kwt": "164.8",
        "type": "21",
        "vin": "WVGZZZ7LZ8D050320",
        "year": "2008"
    }
}
]
Михаил Сисин Со-основатель облачного сервиса по сбору информации и парсингу сайтов Diggernaut. Работает в области сбора и анализа данных, а также разработки систем искусственного интеллекта и машинного обучения  более десяти лет.