Решение Recaptcha методом Grid

Команда 2Captcha регулярно улучшает сервис. 2Captcha предоставляет сервис автоматического решения и обхода reCAPTCHA. Мы внесли улучшения в API для ускорения автоматического решения. Статья описывает внесенные изменения. Прилагаются примеры работы с API сервиса.

В метод в Grid добавленны изменния, которые позволяют решать reCAPTCHA Grid быстрее используя Computer Vision. Используя эти изменения можно значительно сократить время решения капчи, время решения сокращается до нескольких секунд.

Что такое reCAPTCHA v2?

reCAPTCHA v2 — это система защиты, разработанная Google, чтобы отличать людей от ботов. Она предлагает пользователям выполнить простые задачи, такие как найти нужный объект среди 9 изображений или просто поставить галочку в поле «Я не робот».
Цель reCAPTCHA v2 — убедиться, что на сайт зашёл настоящий человек, а не бот, что помогает повысить безопасность и предотвратить спам и мошенничество.

Что нового в API?

В этой статье мы рассмотрим два типа reCAPTCHA и как их решить с помощью API и метода grid.

Теперь метод Grid принимает дополнительный параметр imgType, который используется для направления запроса в соответствующий процесс распознавания в зависимости от типа CAPTCHA. Для reCAPTCHA вам нужно установить его значение на recaptcha.

Как решить reCAPTCHA с использованием метода Grid?

Мы можем разделить процесс на следующие шаги:

  1. Нажатие на флажок
  2. Сбор данных задания
  3. Взаимодействие с API
  4. Нажатие на нужную картинку в сетке

Чтобы нажать на checkbox и картинки сетки, можно использовать подходящие методы вашего любимого инструмента для автоматизации браузера.

В статье мы сосредоточимся на шагах 2 и 3.

Сбор данных

Задание reCAPTCHA с сеткой состоит из:

  • текста задания
  • изображения с применённой сеткой 3x3 или 4x4

Текст задания

Мы можем получить текст из свойства innerText элемента, возвращаемого селектором .rc-imageselect-desc-wrapper, и нам также нужно удалить символы новой строки, чтобы получить весь текст в виде одной строки.

const comment = document.querySelector('.rc-imageselect-desc-wrapper').innerText.replaceAll('\n', ' ')

Картинка 4x4

Этот случай довольно прост, нам просто нужно использовать изображение из элемента, возвращаемого селектором img.rc-image-tile-44.

const img4x4 = document.querySelector('img.rc-image-tile-44')

Картинка 3x3

Изначально все части для сетки 3х3 загружаются как одно изображение, но когда вы нажимаете на изображения, картинки могут быть обновлены новым маленьким изображением, поэтому нам нужно вставить эти обновленные изображения поверх исходного.

Чтобы получить исходное изображение размером 3х3, мы можем использовать селектор: img.rc-image-tile-33, а для получения обновленных фрагментов: img.rc-image-tile-11.

const initial3x3img = table3x3.querySelector('img.rc-image-tile-33')
const updatedTiles = document.querySelectorAll('img.rc-image-tile-11')

Используйте Canvas API, чтобы правильно разместить изображения, а также получить закодированную в base64 версию изображений.

Ниже мы предоставляем функцию на JavaScript, которая поможет вам корректно извлечь данные. Вы можете внедрить этот код в iframe капчи после нажатия на флажок капчи. Затем вызовите функцию getCaptchaData, когда задание капчи станет видимым. Функция возвращает Promise, который завершится и вернёт объект с такими свойствами:

Пример вызова вспомогательной функции:

  • type - тип капчи: GridTask
  • body - извлеченное изображение в виде строки base64
  • comment - текст задания капчи
try {
    let data = await getCaptchaData()
    console.log(JSON.stringify(data))
} catch (e) {
    console.error(e)
}
Helper function code
const getCaptchaData = () => {
    return new Promise((resolve, reject)=>{
        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')
        let comment = document.querySelector('.rc-imageselect-desc-wrapper').innerText.replaceAll('\n', ' ')

        let img4x4 = document.querySelector('img.rc-image-tile-44')
        if (!img4x4) {
            let table3x3 = document.querySelector('table.rc-imageselect-table-33 > tbody')
            if (!table3x3) {
                reject('Can not find reCAPTCHA elements')
            }

            initial3x3img = table3x3.querySelector('img.rc-image-tile-33')

            canvas.width = initial3x3img.naturalWidth
            canvas.height = initial3x3img.naturalHeight
            ctx.drawImage(initial3x3img, 0, 0)

            let updatedTiles = document.querySelectorAll('img.rc-image-tile-11')

            if (updatedTiles.length > 0) {
                const pos = [
                    { x: 0, y: 0 }, { x: ctx.canvas.width / 3, y: 0 }, { x: ctx.canvas.width / 3 * 2, y: 0 },
                    { x: 0, y: ctx.canvas.height / 3 }, { x: ctx.canvas.width / 3, y: ctx.canvas.height / 3 }, { x: ctx.canvas.width / 3 * 2, y: ctx.canvas.height / 3 },
                    { x: 0, y: ctx.canvas.height / 3 * 2 }, { x: ctx.canvas.width / 3, y: ctx.canvas.height / 3 * 2 }, { x: ctx.canvas.width / 3 * 2, y: ctx.canvas.height / 3 * 2 }
                ]
                updatedTiles.forEach((t) => {
                    const ind = t.parentElement.parentElement.parentElement.tabIndex - 3
                    ctx.drawImage(t, pos[ind - 1].x, pos[ind - 1].y)
                })
            }
            resolve({
                rows: 3,
                columns: 3,
                type: 'GridTask',
                comment,
                body: canvas.toDataURL().replace(/^data:image\/?[A-z]*;base64,/, '')
            })
        } else {
            canvas.width = img4x4.clientWidth
            canvas.height = img4x4.clientHeight
            ctx.drawImage(img4x4, 0, 0)
            resolve({
                rows: 4,
                columns: 4,
                comment,
                body: canvas.toDataURL().replace(/^data:image\/?[A-z]*;base64,/, ''),
                type: 'GridTask'
            })
        }
    })
}

Пример результата

{
    "type": "GridTask",
    "body": "/9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZg...",
    "imgType": "recaptcha",
    "rows": 3,
    "columns": 3,
    "comment": "Select all images that have cars in them"
}

Взаимодействие с API

Когда у нас есть все необходимые данные, мы можем сделать запрос к API, чтобы решить капчу. Используйте данные, извлечённые на предыдущем шаге, добавьте параметр imgType, установленный на recaptcha, и укажите количество columns и rows.

Метод: POST
API endpoint: https://api.2captcha.com/createTask

Параметры

Параметр Тип Обязательный Описание
type String Да Тип задачи должен быть установлен в GridTask
imgType String Да Должен быть установлен recaptcha
body String Да Изображение в формате base64 с целым изображением
comment String Да Текст задания на английском
rows Number Да Количество строк, будет 3 или 4
columns Number Да Количество столбцов, будет 3 или 4
imgInstructions String Нет Дополнительное изображение задания (если предоставлено) в формате base64

Пример запроса

{
    "clientKey":"YOUR_API_KEY",
    "task": {
        "type": "GridTask",
        "imgType": "recaptcha",
        "body": "iVBORw0KGgoAAAA...",
        "comment": "Click on the images that best match the theme of the sample image.",
        "rows": 3, // 4
        "columns": 3, // 4
        "imgInstructions": "iVBORw0KGgoAAA..."
    }
}

Пример ответа

{
    "errorId": 0,
    "status": "ready",
    "solution": {
        "click": [
            3,
            4,
            7
        ]
    },
    "cost": "0.0012",
    "ip": "1.2.3.4",
    "createTime": 1692863536,
    "endTime": 1692863556,
    "solveCount": 1
}

Использование

Используйте метод click вашего фреймворка для автоматизации браузера, чтобы нажимать на соответствующие картинки. Селектор для этого — 'div.task'. Обратите внимание, что массив изображений нумеруется с 0, а в ответе нашего API изображения нумеруются с 1 до 9. В нашем примере мы нажимаем на них, используя чистый JavaScript:

document.querySelectorAll('div.task')[3-1].click()
document.querySelectorAll('div.task')[4-1].click()
document.querySelectorAll('div.task')[7-1].click()

Вы также можете использовать наши библиотеки для быстрой реализации этого метода в вашем коде.

Примеры кода библиотек

Ruby
result = client.grid({
  method: 'base64',
  key: 'your_api_key',
  recaptcha: 1,
  json: 1,
  recaptchacols: 3,
  recaptcharows: 3,
  img_type: 'recaptcha',
  textinstructions: 'lease click on all entities similar to the following silhouette',
  imginstructions: Base64.encode64(File.read('path/to/hint.jpg')),
  body: Base64.encode64(File.read('path/to/captcha.jpg')),
  previous_id: 0
})
Python
result = solver.grid( method='base64',
                     body = 'base64',
                     key='your_api_key',
                     recaptcha=1,
                     json=1,
                     recaptchacols=3,
                     recaptcharows=3,
                     img_type='recaptcha',
                     textinstructions='Please click on all entities similar to the following silhouette',
                     imginstructions=base64.b64encode(open('path/to/hint.jpg', 'rb').read()).decode('utf-8'),
                     previous_id=0)

Пример кода c использованием автоматизации браузера