Comparisons

Отличия стандартного и корпоративного решателя reCAPTCHA v2

Со стороны решателя разница между стандартной reCAPTCHA v2 и reCAPTCHA v2 Enterprise умещается в один параметр запроса — enterprise=1. Всё остальное совпадает: тот же метод userrecaptcha, тот же sitekey, тот же опрос res.php, тот же токен в поле g-recaptcha-response.

Почему тогда этот вопрос вообще возникает? Потому что обе версии выглядят в браузере одинаково — тот же флажок «Я не робот», те же сетки со светофорами. Ошибка всплывает позже: токен получен, форма отправлена, а бэкенд сайта его не принимает, и в логах нет ничего внятного. Поэтому начинать стоит не с таблицы различий, а с определения версии на странице.


Как определить reCAPTCHA v2 Enterprise на странице

Признак ровно один — какой файл JavaScript подключает страница. Стандартная версия грузит api.js, Enterprise — enterprise.js. Сам виджет, атрибут data-sitekey и разметка блока идентичны.

Смотрите на тег script:

<!-- Standard v2 -->
<script src="https://www.google.com/recaptcha/api.js"></script>

<!-- Enterprise v2 -->
<script src="https://www.google.com/recaptcha/enterprise.js"></script>

Автоопределение на Python:

import requests
from bs4 import BeautifulSoup

def detect_recaptcha_version(url):
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")

    enterprise_script = soup.find("script", src=lambda s: s and "enterprise.js" in s)
    standard_script = soup.find("script", src=lambda s: s and "recaptcha/api.js" in s)

    widget = soup.find(class_="g-recaptcha")
    sitekey = widget["data-sitekey"] if widget else None

    if enterprise_script:
        return {"version": "enterprise_v2", "sitekey": sitekey}
    elif standard_script:
        return {"version": "standard_v2", "sitekey": sitekey}
    return None

info = detect_recaptcha_version("https://staging.example.com/qa-login")
print(info)

Автоопределение на Node.js:

const axios = require("axios");
const cheerio = require("cheerio");

async function detectRecaptchaVersion(url) {
  const { data } = await axios.get(url);
  const $ = cheerio.load(data);

  const hasEnterprise = $('script[src*="enterprise.js"]').length > 0;
  const hasStandard = $('script[src*="recaptcha/api.js"]').length > 0;
  const sitekey = $(".g-recaptcha").attr("data-sitekey");

  if (hasEnterprise) return { version: "enterprise_v2", sitekey };
  if (hasStandard) return { version: "standard_v2", sitekey };
  return null;
}

Быстрая проверка в консоли браузера:

// Quick check in DevTools
if (document.querySelector('script[src*="enterprise.js"]')) {
  console.log("Enterprise v2");
} else if (document.querySelector('script[src*="recaptcha/api.js"]')) {
  console.log("Standard v2");
}

Проверку стоит делать на каждом запуске, а не один раз при написании скрипта: сайты мигрируют со стандартной v2 на Enterprise без предупреждения, и пайплайн узнает об этом по внезапному потоку отклонённых форм.


Что реально меняет Enterprise: таблица различий

Большая часть отличий живёт на стороне владельца сайта, а не в самой задаче CAPTCHA.

Характеристика Стандартная v2 Enterprise v2
Виджет с флажком Да — внешне неразличимы Да — внешне неразличимы
Задачи с изображениями Сетки 3×3 или 4×4 Сетки 3×3 или 4×4
Подключаемый JS-файл api.js enterprise.js
Функция запуска grecaptcha.execute() grecaptcha.enterprise.execute()
API проверки токена siteverify (бесплатно) recaptchaenterprise.googleapis.com (платно)
Коды причин Нет Да (AUTOMATION, TOO_MUCH_TRAFFIC и др.)
Собственные правила Нет Да (пороги под каждое действие)
Google Cloud Console Нет Да (управление на уровне проекта)
Обнаружение утечек паролей Нет Да
Формат токена Та же структура Та же структура
Параметр в запросе CaptchaAI enterprise=1
Типичное время решения 10–30 с 10–30 с

Читается это так: Enterprise — аналитика и биллинг для владельца сайта, а не более сложная головоломка для пользователя. Коды причин вроде AUTOMATION Google отдаёт бэкенду сайта на этапе верификации: клиент их не видит и обрабатывать их у себя не нужно.


Решение обеих версий через API CaptchaAI

Оба сценария используют метод userrecaptcha: отправляете задачу в in.php, сохраняете ID задачи, опрашиваете res.php до получения токена. Отличается только набор параметров на первом шаге.

Стандартная v2: базовый запрос

import requests
import time

# Submit task
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

# Poll for token
for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

Enterprise v2: тот же запрос плюс флаг

import requests
import time

# Submit task — only difference is enterprise=1
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url,
    "enterprise": 1  # Required for Enterprise
})
task_id = resp.text.split("|")[1]

# Polling is identical
for _ in range(60):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id
    })
    if result.text.startswith("OK|"):
        token = result.text.split("|")[1]
        break

Один класс на обе версии

Если стендов больше одного, держать две ветки кода нет смысла. Проще собрать обёртку, которая сама смотрит HTML, решает, нужен ли флаг, и возвращает токен вместе с признаком версии.

import requests
import time
from bs4 import BeautifulSoup

class RecaptchaV2Solver:
    def __init__(self, api_key):
        self.api_key = api_key

    def detect_and_solve(self, page_url, page_html=None):
        if not page_html:
            page_html = requests.get(page_url).text

        soup = BeautifulSoup(page_html, "html.parser")
        is_enterprise = bool(soup.find("script", src=lambda s: s and "enterprise.js" in s))
        widget = soup.find(class_="g-recaptcha")
        sitekey = widget["data-sitekey"] if widget else None

        if not sitekey:
            raise Exception("No reCAPTCHA sitekey found on page")

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url
        }
        if is_enterprise:
            params["enterprise"] = 1

        resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {resp.text}")

        task_id = resp.text.split("|")[1]

        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key, "action": "get", "id": task_id
            })
            if result.text.startswith("OK|"):
                return {
                    "token": result.text.split("|")[1],
                    "is_enterprise": is_enterprise,
                    "sitekey": sitekey
                }
            if result.text != "CAPCHA_NOT_READY":
                raise Exception(f"Solve failed: {result.text}")

        raise Exception("Solve timed out")


solver = RecaptchaV2Solver("YOUR_API_KEY")
result = solver.detect_and_solve("https://staging.example.com/qa-login")
print(f"Enterprise: {result['is_enterprise']}, Token: {result['token'][:40]}...")

Передача токена во внутренний QA endpoint

Здесь разницы между версиями нет вообще. Порядок действий один и тот же:

  1. Положить токен в поле g-recaptcha-response.
  2. Прочитать у виджета атрибут data-callback.
  3. Если callback объявлен — вызвать его явно, передав тот же токен.

Третий шаг пропускают чаще всего. Без него форма остаётся в состоянии «капча не пройдена», хотя значение в скрытом поле уже подставлено.

На Selenium это выглядит так:

# Selenium injection — works for both standard and enterprise
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# If the page uses a callback function
callback = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
if callback:
    driver.execute_script(f'{callback}("{token}");')

В Puppeteer обе операции удобно выполнить одним page.evaluate:

// Puppeteer injection — works for both
await page.evaluate((token) => {
  document.getElementById("g-recaptcha-response").value = token;
  // Find and call callback if present
  const widget = document.querySelector(".g-recaptcha");
  const cb = widget?.getAttribute("data-callback");
  if (cb && typeof window[cb] === "function") {
    window[cb](token);
  }
}, token);

Где чаще всего ошибаются

Ошибка Что происходит Как исправить
enterprise=1 отправлен для стандартной v2 Токен может оказаться невалидным Перед добавлением флага проверьте наличие enterprise.js
enterprise=1 забыт для Enterprise v2 Бэкенд сайта отклоняет токен Добавляйте флаг всегда, когда видите enterprise.js
Взят не тот sitekey ERROR_WRONG_GOOGLEKEY Читайте data-sitekey с элемента .g-recaptcha, а не из чужого примера
v2 Enterprise перепутана с v3 Enterprise Неверные параметры задачи У v2 есть флажок; v3 невидима и возвращает score
Версия зашита в коде жёстко Пайплайн ломается после миграции сайта Определяйте версию на каждом запуске

Сколько потоков нужно под такую задачу

Типичный сценарий для команд в Москве, Минске или Алматы: ночной регресс по десятку staging-стендов, где часть форм уже переехала на Enterprise, а часть ещё на стандартной v2. При времени решения 10–30 с один поток даёт порядка 120–360 решений в час, так что для ночного прогона на несколько тысяч проверок хватает небольшого тарифа.

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

  • BASIC ($15/мес, 5 потоков) — один проект, ночной регресс, ручные прогоны.
  • STANDARD ($30/мес, 15 потоков) — несколько стендов и параллельные воркеры в CI.
  • ADVANCE ($90/мес, 50 потоков) — регулярный парсинг или несколько клиентских проектов сразу.

Полная сетка тарифов доходит до VIP-3 ($7,500/мес, 5000 потоков); актуальные цены смотрите на странице тарифов CaptchaAI.

Отдельно о данных: если стенд работает с реальными анкетами пользователей, собирайте только те данные, которые вы вправе обрабатывать — для читателей в РФ это вопрос 152-ФЗ «О персональных данных», для трансграничных проектов — GDPR. На тестовых стендах проще всего держать синтетические учётные записи.


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

Как быстро понять, какая версия стоит на странице?

Откройте DevTools и поищите во вкладке Network запрос к enterprise.js. Если он есть — это Enterprise, если есть только recaptcha/api.js — стандартная v2. В автоматизации ту же проверку делает парсер HTML из примеров выше.

Что делать, если токен получен, а форма всё равно не проходит?

Проверьте два места:

  • Совпадает ли флаг enterprise=1 с реальной версией на странице.
  • Вызван ли data-callback виджета после подстановки токена — без этого многие формы считают проверку незавершённой.

В логи стоит писать признак версии рядом с ID задачи: тогда разбор такого случая занимает минуту, а не полдня.

Сколько времени закладывать на решение в таймаутах CI?

Ориентируйтесь на 10–30 с на задачу для обеих версий и ставьте верхнюю границу с запасом: примеры выше опрашивают res.php с шагом 5 с. Жёсткий тайм-аут в 10 с будет регулярно ронять зелёные прогоны на медленном канале.

Нужно ли менять тариф ради Enterprise-сайтов?

Нет. Тарифы считаются по потокам, а не по типам CAPTCHA, надбавок за отдельный тип нет. Менять тариф имеет смысл, когда растёт число параллельных задач, а не когда сайт перешёл на Enterprise.

Подходит ли этот же подход к другим типам проверок?

Схема «отправил задачу → опросил результат → подставил токен» одинакова для всех поддерживаемых типов, меняются только метод и параметры. При планировании покрытия тестов держите в голове три группы:

  • Решаются: reCAPTCHA v2 и v3, Cloudflare Turnstile и Challenge, GeeTest v3, image/OCR, текстовые и grid-капчи, BLS CAPTCHA.
  • В бета-режиме: CaptchaFox (beta), Friendly Captcha (beta), Lemin (beta).
  • Не решаются: hCaptcha и FunCaptcha; GeeTest v4 пока в статусе «скоро».

Связанные материалы

Если вы разбираете чужую вёрстку и вам нужен пошаговый чек-лист признаков, начните с материала про определение reCAPTCHA Enterprise, а затем возвращайтесь к списку ниже.

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