Troubleshooting

Обработка reCAPTCHA v2 и v3 на одной странице

На некоторых веб-сайтах на одной странице реализованы как reCAPTCHA v2, так и v3. Типичная схема такова: версия 3 незаметно работает в фоновом режиме, и если оценка слишком низкая, версия 2 отображается как видимая резервная задача. Такая двойная реализация создает путаницу для автоматизации, поскольку вам приходится обрабатывать два разных типа CAPTCHA с разными методами решения. В этом руководстве рассматриваются стратегии обнаружения, решения и распространенные крайние случаи.


Почему сайты используют версии 2 и 3 вместе

User visits page
    ↓
reCAPTCHA v3 runs invisibly in background
    ↓
Score returned to server (e.g., 0.4)
    ↓
Score below threshold (e.g., < 0.7)?
    ├─ YES → Show reCAPTCHA v2 checkbox/image challenge
    └─ NO  → Allow action without visible CAPTCHA

Этот шаблон сочетает в себе подходящий из обоих миров:

  • Большинство пользователей (высокий балл v3) не видят CAPTCHA → низкий уровень сложности
  • Подозрительные пользователи (низкий балл v3) видят вызов v2. Резервный вариант безопасности →.
  • Оператор веб-сайта контролирует порог между невидимым и видимым

Двойные шаблоны реализации

Схема 1: предварительная оценка версии 3 + резервная версия версии 2

Самый распространенный узор. Версия 3 запускается первой, а версия 2 появляется только при необходимости.

<!-- Both scripts loaded -->
<script src="https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY"></script>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>

<form id="loginForm">
    <!-- v2 widget (hidden initially) -->
    <div id="recaptcha-v2-container" style="display:none;">
        <div class="g-recaptcha" data-sitekey="V2_SITE_KEY"></div>
    </div>
    <button type="submit">Login</button>
</form>

<script>
// First attempt: v3 invisible
grecaptcha.ready(function() {
    grecaptcha.execute('V3_SITE_KEY', {action: 'login'}).then(function(v3Token) {
        fetch('/api/verify-v3', {
            method: 'POST',
            body: JSON.stringify({token: v3Token})
        })
        .then(r => r.json())
        .then(data => {
            if (data.score < 0.7) {
                // Score too low → show v2 fallback
                document.getElementById('recaptcha-v2-container').style.display = 'block';
                grecaptcha.render('recaptcha-v2-container', {sitekey: 'V2_SITE_KEY'});
            } else {
                // Score OK → submit form directly
                document.getElementById('loginForm').submit();
            }
        });
    });
});
</script>

Схема 2. Разные ключи сайта для разных действий.

Некоторые сайты используют версию 3 для пассивного мониторинга и версию 2 для конкретных действий с высоким уровнем риска:

Homepage → v3 only (passive score)
Login page → v3 assessment, v2 fallback
Checkout → v2 always (high security)
Contact form → v3 only

Схема 3: один сценарий, двойной режим

Google поддерживает загрузку одного скрипта reCAPTCHA, который обрабатывает как v2, так и v3:

<script src="https://www.google.com/recaptcha/api.js?render=V3_SITE_KEY"></script>
<script>
    // v3 execute
    grecaptcha.execute('V3_SITE_KEY', {action: 'login'});

    // v2 render (uses a different site key)
    grecaptcha.render('v2-container', {sitekey: 'V2_SITE_KEY'});
</script>

Обнаружение двойной реализации

Обнаружение Python

import requests
import re

def detect_dual_recaptcha(url):
    """Detect if a page uses both reCAPTCHA v2 and v3."""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/120.0.0.0 Safari/537.36",
    }
    html = requests.get(url, headers=headers, timeout=15).text

    result = {
        "has_v3": False,
        "has_v2": False,
        "v3_site_key": None,
        "v2_site_key": None,
        "dual": False,
        "pattern": None,
    }

    # Detect v3 (render parameter or enterprise.execute)
    v3_match = re.search(r"api\.js\?render=([A-Za-z0-9_-]+)", html)
    if v3_match and v3_match.group(1) != "explicit":
        result["has_v3"] = True
        result["v3_site_key"] = v3_match.group(1)

    # Detect v3 in execute calls
    v3_execute = re.search(
        r"grecaptcha\.(?:enterprise\.)?execute\s*\(\s*['\"]([^'\"]+)['\"]",
        html,
    )
    if v3_execute:
        result["has_v3"] = True
        if not result["v3_site_key"]:
            result["v3_site_key"] = v3_execute.group(1)

    # Detect v2 (g-recaptcha class or explicit render)
    v2_match = re.search(r'data-sitekey="([^"]+)"', html)
    if v2_match:
        key = v2_match.group(1)
        if key != result.get("v3_site_key"):
            result["has_v2"] = True
            result["v2_site_key"] = key

    # Check for explicit v2 render
    v2_render = re.search(
        r"grecaptcha\.render\s*\([^,]+,\s*\{[^}]*sitekey:\s*['\"]([^'\"]+)",
        html,
    )
    if v2_render:
        result["has_v2"] = True
        if not result["v2_site_key"]:
            result["v2_site_key"] = v2_render.group(1)

    result["dual"] = result["has_v3"] and result["has_v2"]

    if result["dual"]:
        # Determine pattern
        if "display:none" in html or "display: none" in html:
            result["pattern"] = "v3_pre_assessment_v2_fallback"
        else:
            result["pattern"] = "v2_v3_simultaneous"

    return result

detection = detect_dual_recaptcha("https://https://staging.example.com/qa-login")
print(detection)

Обнаружение Node.js

const axios = require("axios");

async function detectDualRecaptcha(url) {
    const { data: html } = await axios.get(url, { timeout: 15000 });

    const result = {
        hasV3: false,
        hasV2: false,
        v3SiteKey: null,
        v2SiteKey: null,
        dual: false,
    };

    // v3 detection
    const v3Match = html.match(/api\.js\?render=([A-Za-z0-9_-]+)/);
    if (v3Match && v3Match[1] !== "explicit") {
        result.hasV3 = true;
        result.v3SiteKey = v3Match[1];
    }

    // v2 detection
    const v2Match = html.match(/data-sitekey="([^"]+)"/);
    if (v2Match && v2Match[1] !== result.v3SiteKey) {
        result.hasV2 = true;
        result.v2SiteKey = v2Match[1];
    }

    result.dual = result.hasV3 && result.hasV2;
    return result;
}

detectDualRecaptcha("https://https://staging.example.com/qa-login").then(console.log);

Решение стратегий двойной reCAPTCHA

Стратегия 1: сначала решите версию 3, затем, если необходимо, версию 2.

Оптимальная стратегия отражает собственный поток сайта:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_v3(site_key, page_url, action="login"):
    """Solve reCAPTCHA v3 and return token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "version": "v3",
        "action": action,
        "json": 1,
    }).json()

    task_id = submit["request"]

    for _ in range(60):
        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"]

    raise TimeoutError("v3 solve timeout")

def solve_v2(site_key, page_url):
    """Solve reCAPTCHA v2 and return token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1,
    }).json()

    task_id = submit["request"]

    for _ in range(60):
        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"]

    raise TimeoutError("v2 solve timeout")

def solve_dual_recaptcha(v3_key, v2_key, page_url, action="login"):
    """Handle dual reCAPTCHA: try v3, fall back to v2."""
    # Step 1: Try v3
    v3_token = solve_v3(v3_key, page_url, action)

    # Step 2: Submit v3 token to target
    response = requests.post(f"{page_url}/verify", data={
        "g-recaptcha-response": v3_token,
    })

    # Step 3: Check if v2 fallback is needed
    if "recaptcha" in response.text.lower() and v2_key:
        print("v3 score too low — v2 fallback triggered")
        v2_token = solve_v2(v2_key, page_url)
        return {"version": "v2", "token": v2_token}

    return {"version": "v3", "token": v3_token}

result = solve_dual_recaptcha(
    v3_key="6LcExample_v3_key",
    v2_key="6LcExample_v2_key",
    page_url="https://https://staging.example.com/qa-login",
)
print(f"Solved with {result['version']}")

Стратегия 2: Пропустить версию 3, решить версию 2 напрямую.

Если вы знаете, что сайт всегда показывает версию 2 для автоматического трафика (оценка версии 3 будет низкой), пропустите версию 3 и немедленно решите проблему версии 2:

# If you consistently fail v3 assessment, just solve v2 directly
token = solve_v2(v2_site_key, page_url)
submit_form(token)

Это экономит время и затраты на решение версии 3, которое может не преодолеть порог.

Стратегия 3. Обработка через браузер.

Для сложных реализаций используйте браузер для обработки резервного потока:

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

driver = webdriver.Chrome()
driver.get("https://https://staging.example.com/qa-login")
time.sleep(3)

# Check if v2 widget is visible
v2_visible = driver.execute_script("""
    const container = document.querySelector('.g-recaptcha');
    if (!container) return false;
    const style = window.getComputedStyle(container.parentElement);
    return style.display !== 'none' && style.visibility !== 'hidden';
""")

if v2_visible:
    # v2 is showing — solve v2
    sitekey = driver.find_element(
        By.CSS_SELECTOR, "[data-sitekey]"
    ).get_attribute("data-sitekey")
    token = solve_v2(sitekey, driver.current_url)
    driver.execute_script(
        f'document.getElementById("g-recaptcha-response").value = "{token}";'
    )
else:
    # v3 only — solve v3
    # Extract v3 key from page source
    v3_key = driver.execute_script(
        "return document.querySelector('script[src*=\"render=\"]')"
        ".src.match(/render=([^&]+)/)[1];"
    )
    token = solve_v3(v3_key, driver.current_url)
    # Inject v3 token into the form
    driver.execute_script(f"""
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = 'g-recaptcha-response';
        input.value = '{token}';
        document.querySelector('form').appendChild(input);
    """)

driver.find_element(By.CSS_SELECTOR, "form").submit()

Краевые случаи

Два разных ключа сайта на одной странице

Сайты, использующие двойную reCAPTCHA, будут иметь ДВА разных ключа сайта — один для версии 3 и один для версии 2. Ключ v3 появляется в URL-адресе сценария ?render=KEY и в grecaptcha.execute('KEY', ...). Ключ v2 отображается в data-sitekey="KEY" в div виджета. Использование неправильного ключа для неправильной версии приведет к созданию недействительных токенов.

reCAPTCHA Enterprise с резервной версией v2

В некоторых реализациях Enterprise используется версия 3 Enterprise для оценки и версия 2 для задач:

# Detect and handle Enterprise + v2 combo
if "recaptcha/enterprise.js" in html:
    # Use enterprise parameter for v3
    v3_params = {"enterprise": 1, "version": "v3"}
else:
    v3_params = {"version": "v3"}

Несколько форм на одной странице

Если на странице несколько форм (вход + регистрация), у каждой может быть свой экземпляр reCAPTCHA. Извлеките ключ сайта из конкретной формы, на которую вы ориентируетесь:

# Target the login form specifically
login_form = soup.find("form", id="login-form")
widget = login_form.find(attrs={"data-sitekey": True})
sitekey = widget["data-sitekey"]

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

Нужно ли мне решать v2 и v3 на одной странице?

Нет. Обычно сначала вы решаете версию 3 (она запускается автоматически). Если оценка v3 превышает пороговое значение сайта, задача v2 не отображается, и все готово. Вам нужно решить v2 только в том случае, если оценка v3 вызывает откат.

Могу ли я использовать один вызов API CaptchaAI для двойной reCAPTCHA?

№ v2 и v3 — это отдельные типы CAPTCHA с разными ключами сайта и методами решения. Для каждого требуется собственный вызов API для CaptchaAI. Однако вам нужно сделать только один вызов, если v3 пройдет без запуска v2.

Как узнать, сработал ли резервный вариант версии 2?

Проверьте ответ сервера после отправки токена v3. Если ответ содержит HTML-код виджета версии 2 или запускает запрос версии 2 (перенаправление или ответ AJAX с HTML-кодом CAPTCHA), срабатывает резервный вариант. В браузере проверьте, становится ли контейнер версии 2 видимым после отправки версии 3.

Какой ключ сайта мне использовать для каждой версии?

Ключ сайта v3 находится в URL-адресе сценария: api.js?render=V3_KEY. Ключ сайта v2 находится в HTML виджета: data-sitekey="V2_KEY". Это всегда разные ключи.


Краткое содержание

Реализации двойной reCAPTCHA используют версию 3 для невидимой предварительной оценки и версию 2 в качестве видимого запасного варианта, когда оценка версии 3 слишком низкая. Обнаружьте обе версии, проверив параметр рендеринга (v3) и ключ сайта данных виджета (v2). Оптимальная стратегия автоматизации: сначала решить v3 с помощьюCaptchaAI, отправьте токен и решите проблему v2 только в том случае, если сработает резервный вариант. Для каждой версии требуется отдельный вызов API со своим ключом сайта.

Похожие статьи

  • Динамическое одностраничное приложение Recaptcha
  • Как решить обратный вызов Recaptcha V2 с помощью API
  • Cloudflare Turnstile Recaptcha V2. Обработка на той же площадке.
Комментарии для этой статьи отключены.