API Tutorials

Как автоматически решать CAPTCHA с изображением сетки

Сетка 3×3 с подписью «выберите нужные ячейки» — не всегда reCAPTCHA. Многие сайты строят собственную проверку по сетке изображений, никак не связанную с системой Google, и решать её нужно другим методом. Ниже — рабочая схема на конечной точке method=post (recaptcha=1) CaptchaAI: как снять сетку, отправить её на решение, дождаться ответа и применить его в браузере.


Когда нужен именно метод сетки

Токен reCAPTCHA (method=userrecaptcha) подходит только для официальных проверок Google. Если сайт рисует собственную сетку — например, кастомная форма регистрации, внутренний QA-стенд маркетплейса или портал с визовыми/административными формами — токена там нет, и решать нужно само изображение целиком через method=post.

Пример из практики: команда QA в Минске или Алматы тестирует staging-версию формы регистрации, которую разработчики закрыли собственной сеткой изображений, чтобы отсечь ботов ещё до продакшена. Для одного браузера с последовательными запросами хватает тарифа BASIC ($15/мес, 5 потоков) — а когда параллельных Selenium-сессий становится больше, поток просто увеличивают до STANDARD ($30/мес, 15 потоков) или выше, без смены логики кода.


Что понадобится

  • API-ключ CaptchaAI — получите на captchaai.com.
  • Изображение сетки — скриншот или base64 всей сетки целиком, без обрезки по краям.
  • Среда выполнения — Python 3.7+ или Node.js 14+.
  • HTTP-клиентrequests для Python или axios для Node.js.

Шаг 1. Снимите изображение сетки

Проще всего снять именно контейнер капчи через Selenium, а не всю страницу целиком — лишние поля вокруг сетки только увеличивают вес файла и не помогают распознаванию:

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com/protected-form")

# Screenshot just the captcha container
captcha_element = driver.find_element(By.CSS_SELECTOR, "#captcha-container")
captcha_element.screenshot("captcha_grid.png")

Если сетка отдаётся картинкой в DOM, быстрее вытащить её прямо из атрибута src, не делая скриншот отдельным шагом. Когда изображение уже закодировано как data:image base64, доставать байты через requests вообще не нужно — это экономит один сетевой запрос:

import base64
import requests

captcha_img = driver.find_element(By.CSS_SELECTOR, ".grid-captcha img")
src = captcha_img.get_attribute("src")

if src.startswith("data:image"):
    image_b64 = src.split(",")[1]
else:
    image_data = requests.get(src).content
    image_b64 = base64.b64encode(image_data).decode()

Шаг 2. Отправьте изображение в CaptchaAI

Загрузка файлом удобна для отладки — видно, что именно ушло на решение:

import requests
import time

API_KEY = "YOUR_API_KEY"

with open("captcha_grid.png", "rb") as f:
    response = requests.post("https://ocr.captchaai.com/in.php",
        data={
            "key": API_KEY,
            "method": "post",
            "recaptcha": 1,
            "json": 1
        },
        files={"file": f}
    )

data = response.json()
task_id = data["request"]
print(f"Task: {task_id}")

Для serverless-обработчиков без файловой системы удобнее base64 — байты передаются прямо в теле запроса:

response = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "post",
    "body": image_b64,
    "recaptcha": 1,
    "json": 1
})

task_id = response.json()["request"]

На Node.js логика та же самая: собрать base64 и отправить его в in.php c теми же параметрами method и recaptcha:

const axios = require('axios');
const fs = require('fs');

async function submitGridCaptcha(imagePath) {
  const imageB64 = fs.readFileSync(imagePath).toString('base64');

  const { data } = await axios.post('https://ocr.captchaai.com/in.php', null, {
    params: {
      key: 'YOUR_API_KEY',
      method: 'post',
      body: imageB64,
      recaptcha: 1,
      json: 1
    }
  });

  return data.request;
}

Все три варианта возвращают один и тот же task_id — выбирайте тот, что проще встраивается в уже существующий пайплайн.


Шаг 3. Опросите res.php и получите решение

def get_grid_solution(task_id):
    for _ in range(30):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1
        }).json()

        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise Exception(f"Error: {result['request']}")

    raise Exception("Timeout")

solution = get_grid_solution(task_id)
print(f"Solution: {solution}")
# Returns click coordinates or cell indices

Опрос идёт с интервалом 5 секунд до 30 попыток — этого запаса хватает с большим резервом, но при регулярных таймаутах сначала проверьте размер и чёткость самого изображения, а не увеличивайте число попыток.


Шаг 4. Примените решение в браузере

Если CaptchaAI вернул индексы ячеек, кликайте по соответствующим элементам .grid-cell напрямую:

# If solution returns cell indices (e.g., "2,5,6")
selected = [int(i) for i in solution.split(",")]
cells = driver.find_elements(By.CSS_SELECTOR, ".grid-cell")

for idx in selected:
    cells[idx - 1].click()
    time.sleep(0.2)

driver.find_element(By.CSS_SELECTOR, ".verify-button").click()

Если вместо индексов пришли пиксельные координаты, кликайте через ActionChains со смещением от контейнера капчи:

from selenium.webdriver.common.action_chains import ActionChains

# If solution returns coordinates (e.g., "x=120,y=80;x=250,y=200")
captcha_element = driver.find_element(By.CSS_SELECTOR, "#captcha-container")
actions = ActionChains(driver)

for coord in solution.split(";"):
    parts = dict(p.split("=") for p in coord.split(","))
    x, y = int(parts["x"]), int(parts["y"])
    actions.move_to_element_with_offset(captcha_element, x, y).click()

actions.perform()

Формат ответа зависит от конкретного сайта, а не от CaptchaAI — проверьте оба варианта заранее на тестовой сетке, а не в продакшен-коде, чтобы не гадать по логам через месяц.


Как встроить это в конвейер автоматизации

Метод сетки редко живёт в вакууме — обычно это один узел внутри более крупного QA- или парсинг-пайплайна на Selenium, Playwright или Puppeteer. Несколько практических моментов, которые стоит заложить сразу, а не после первого падения в проде:

  • Оборачивайте вызов in.php/res.php в повтор с экспоненциальной задержкой, а не с фиксированным интервалом — сетевые сбои и кратковременные CAPCHA_NOT_READY не должны валить весь тест-ран.
  • Логируйте task_id вместе с URL страницы и временем отправки — это единственный надёжный способ разобраться, какая именно сетка не решилась, если ошибка всплывает через час после прогона.
  • Считайте потоки заранее: число одновременных браузерных сессий не должно превышать число оплаченных потоков тарифа — иначе лишние задачи просто встанут в очередь и увеличат общее время прогона, а не ускорят его.
  • Держите таймаут ожидания решения отдельным от общего таймаута теста — 30 попыток по 5 секунд из примера выше — это тайм-бюджет самого решателя, а не всего сценария целиком.

Готовый пример и типичные ошибки

Нужен полноценный рабочий проект с настройкой окружения, опросом, повторами и обработкой ошибок «из коробки»? Полный пример на GitHub →

Прежде чем тащить код в продакшен, сверьтесь с частыми причинами отказа:

  • ERROR_WRONG_FILE_EXTENSION — неверный формат изображения. Используйте PNG или JPEG и проверьте, что base64 валиден.
  • ERROR_CAPTCHA_UNSOLVABLE — изображение слишком маленькое или размытое. Снимайте в полном разрешении, а не миниатюру.
  • Выбраны не те ячейки — формат решения не совпал с ожидаемым. Проверьте, индексы это или координаты, прежде чем маппить их на DOM.
  • ERROR_TOO_BIG_CAPTCHA_FILESIZE — изображение превышает лимит размера. Сожмите файл до 600 КБ и меньше, не теряя чёткости.

Часто задаваемые вопросы

Когда использовать метод сетки, а не токен reCAPTCHA?

Токен (method=userrecaptcha) — для стандартных проверок reCAPTCHA: он проще и надёжнее там, где Google действительно участвует в проверке. Метод сетки (method=post с recaptcha=1) — для кастомных проверок с изображением, не связанных с reCAPTCHA, и для отдельных сеток без токена вовсе.

Что делать с динамической сеткой, где плитки заменяются после клика?

Это признак именно reCAPTCHA, а не самостоятельной сетки: там кликнутые плитки подгружаются заново. В таком случае нужен токен-метод (method=userrecaptcha). Метод сетки, описанный в этом руководстве, рассчитан на одно статичное изображение — если плитки меняются на лету, он не подойдёт.

Сколько потоков CaptchaAI нужно для конвейера с сетками?

Grid Image решается быстро — менее секунды по официальным метрикам CaptchaAI — с высокой долей успешных решений на поддерживаемых типах, поэтому throughput почти всегда упирается в параллелизм самого браузера, а не в скорость решателя. Для одного-двух Selenium-воркеров хватает BASIC ($15/мес, 5 потоков); при росте числа параллельных сессий переходите на STANDARD ($30/мес, 15 потоков) или ADVANCE ($90/мес, 50 потоков) — тарифы включают неограниченное число решений на поток.

Как ускорить пакетную обработку большого числа сеток?

Держите каждый файл под 600 КБ, отправляйте задачи параллельно — по числу оплаченных потоков — и снимайте сетку в полном разрешении сразу, а не масштабируйте её позже: пересжатие после захвата обычно и роняет точность распознавания.

Нужен ли отдельный API-ключ для метода сетки?

Нет — ключ один и тот же для всех методов CaptchaAI. method=post с recaptcha=1 — это просто другой набор параметров того же in.php, а не отдельный продукт или отдельная авторизация.


Похожие материалы

Комментарии для этой статьи отключены.