Сетка 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, а не отдельный продукт или отдельная авторизация.