Troubleshooting

浏览器自动化验证码失败但 API 有效:调试指南

您通过 CaptchaAI 解决了验证码并获得了有效令牌,但将其注入浏览器不起作用。本指南涵盖了每个问题的所有原因以及解决方法。


常见故障点

问题 症状 根本原因
令牌未注入正确的元素 表单提交时无需令牌 错误的文本区域选择器
提交前令牌已过期 网站再次显示验证码 解决和提交之间太慢
回调未触发 表单按钮保持禁用状态 缺少 grecaptcha 回调
发送到 API 的页面 URL 错误 令牌对该域无效 网址不匹配
超越验证码的机器人检测 接受令牌后被阻止 浏览器特征

修复 1:正确注入 reCAPTCHA v2 的代币

令牌必须进入 g-recaptcha-response 文本区域并且回调必须触发:

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


def inject_recaptcha_token(driver, token):
    """Properly inject reCAPTCHA v2 token in browser."""

    # Step 1: Make the response textarea visible and set the value
    driver.execute_script("""
        // Find all response textareas (may be multiple on page)
        var textareas = document.querySelectorAll('[name="g-recaptcha-response"]');
        textareas.forEach(function(ta) {
            ta.style.display = 'block';
            ta.value = arguments[0];
        });

        // Also set via ID if present
        var byId = document.getElementById('g-recaptcha-response');
        if (byId) {
            byId.style.display = 'block';
            byId.value = arguments[0];
        }
    """, token)

    # Step 2: Trigger the callback
    driver.execute_script("""
        // Try standard callback
        if (typeof ___grecaptcha_cfg !== 'undefined') {
            var clients = ___grecaptcha_cfg.clients;
            for (var key in clients) {
                var client = clients[key];
                // Navigate nested structure to find callback
                for (var prop in client) {
                    var val = client[prop];
                    if (val && typeof val === 'object') {
                        for (var subprop in val) {
                            var subval = val[subprop];
                            if (subval && typeof subval === 'object' && subval.callback) {
                                subval.callback(arguments[0]);
                                return;
                            }
                        }
                    }
                }
            }
        }
        // Fallback: try common callback names
        if (typeof onCaptchaSuccess === 'function') onCaptchaSuccess(arguments[0]);
        else if (typeof captchaCallback === 'function') captchaCallback(arguments[0]);
    """, token)


# Usage
driver = webdriver.Chrome()
driver.get("https://example.com/form")
# ... solve CAPTCHA via CaptchaAI ...
inject_recaptcha_token(driver, token)
time.sleep(1)
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()

修复 2:处理回调相关表单

某些表单在验证码回调触发之前保持禁用状态:

def find_and_trigger_callback(driver, token):
    """Find the reCAPTCHA callback and trigger it."""

    # Method 1: Extract callback from data attribute
    callback_name = driver.execute_script("""
        var widget = document.querySelector('.g-recaptcha');
        if (widget) {
            return widget.getAttribute('data-callback');
        }
        return null;
    """)

    if callback_name:
        driver.execute_script(f"window['{callback_name}'](arguments[0]);", token)
        return True

    # Method 2: Extract from grecaptcha config
    triggered = driver.execute_script("""
        try {
            var widgetId = 0;
            var callback = ___grecaptcha_cfg.clients[widgetId].aa.l.callback;
            if (typeof callback === 'function') {
                callback(arguments[0]);
                return true;
            }
        } catch(e) {}
        return false;
    """, token)

    return triggered

修复 3:时机 — 立即解决并使用

import requests
import time


def solve_and_inject_fast(driver, api_key, sitekey, page_url):
    """Solve CAPTCHA and inject token with minimal delay."""
    # Submit solve request
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "json": 1,
    }, timeout=30)
    task_id = resp.json()["request"]

    # Poll for result
    time.sleep(15)
    for _ in range(24):
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15)
        data = resp.json()

        if data.get("status") == 1:
            token = data["request"]

            # IMMEDIATELY inject — don't wait
            inject_recaptcha_token(driver, token)

            # Submit form within 5 seconds
            time.sleep(0.5)
            return True

        if data["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(data["request"])
        time.sleep(5)

    raise TimeoutError("Solve timeout")

修复 4:正确的 SPA 和 Iframe 的 pageurl

def get_correct_pageurl(driver):
    """Get the URL that reCAPTCHA actually sees."""

    # Check if CAPTCHA is in an iframe
    iframes = driver.find_elements(By.TAG_NAME, "iframe")

    for iframe in iframes:
        src = iframe.get_attribute("src") or ""
        if "recaptcha" in src or "anchor" in src:
            # CAPTCHA is in iframe — use parent page URL
            return driver.current_url

    # For SPAs, use current URL (may differ from initial load)
    return driver.current_url


# WRONG — using the URL you navigated to
pageurl = "https://example.com/form"  # May have redirected

# CORRECT — using the URL the browser is actually on
pageurl = get_correct_pageurl(driver)

修复 5:验证码之外的反机器人检测

即使拥有有效的令牌,该网站也可能会阻止自动浏览器:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service


def create_stealth_driver():
    """Create a browser that avoids basic bot detection."""
    options = Options()

    # Remove automation indicators
    options.add_argument("--no-sandbox")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option("useAutomationExtension", False)

    # Set realistic window size
    options.add_argument("--window-size=1920,1080")

    driver = webdriver.Chrome(options=options)

    # Override navigator.userAgent
    driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        "source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
    })

    return driver


driver = create_stealth_driver()

修复 6:旋转栅门token 提交

Cloudflare Turnstile 使用不同的注入方法:

def inject_turnstile_token(driver, token):
    """Inject Turnstile token into the page."""
    driver.execute_script("""
        // Find Turnstile response input
        var inputs = document.querySelectorAll(
            'input[name="cf-turnstile-response"], ' +
            'input[name="g-recaptcha-response"]'
        );

        inputs.forEach(function(input) {
            input.value = arguments[0];
        });

        // Trigger change event
        inputs.forEach(function(input) {
            input.dispatchEvent(new Event('change', { bubbles: true }));
            input.dispatchEvent(new Event('input', { bubbles: true }));
        });

        // Try Turnstile callback
        if (window.turnstile) {
            var widgets = document.querySelectorAll('[data-callback]');
            widgets.forEach(function(w) {
                var cb = w.getAttribute('data-callback');
                if (typeof window[cb] === 'function') {
                    window[cb](arguments[0]);
                }
            });
        }
    """, token)

调试清单

def debug_captcha_injection(driver, token):
    """Print debug info to diagnose injection failures."""
    info = driver.execute_script("""
        var result = {};

        // Check textarea exists
        var ta = document.querySelector('[name="g-recaptcha-response"]');
        result.textarea_found = !!ta;
        result.textarea_value_set = ta ? ta.value.length > 0 : false;

        // Check reCAPTCHA loaded
        result.grecaptcha_loaded = typeof grecaptcha !== 'undefined';

        // Check for callback
        var widget = document.querySelector('.g-recaptcha');
        result.has_data_callback = widget ? !!widget.getAttribute('data-callback') : false;
        result.callback_name = widget ? widget.getAttribute('data-callback') : null;

        // Current URL
        result.current_url = window.location.href;

        // Check for errors in console (basic)
        result.has_submit_button = !!document.querySelector('button[type=submit], input[type=submit]');

        return result;
    """)

    for key, value in info.items():
        print(f"  {key}: {value}")

    return info

故障排除

症状 原因 处理方式
令牌已设置但表单被拒绝 回调未触发 查找并调用回调函数
提交按钮保持禁用状态 回调启用它 token注入后触发回调
提交后提示“验证码无效” 令牌已过期 减少解决和提交之间的时间
表单提交后403 机器人检测(不是验证码) 使用隐形浏览器选项
在请求中有效,在浏览器中失败 不同的页面网址 使用 driver.current_url 作为 pageurl

常问问题

为什么令牌在请求中起作用,但在浏览器中不起作用?

通常是因为回调函数没有被触发。浏览器表单通常依赖回调来启用提交或设置隐藏字段。

我需要使用特定的浏览器吗?

Chrome/Chromium 是最兼容的。 Firefox 可以工作,但可能需要不同的 CDP 命令方法。对于具有强大机器人检测功能的网站,请使用 unDetected-chromedriver。

我应该使用无头模式吗?

一些站点检测无头浏览器并拒绝令牌。首先尝试 headful 模式,如果可行的话,然后使用适当的标志切换到 headless 模式。


相关指南



后续阅读

  • CaptchaAI 快速上手:5 分钟解决你的第一个验证码
  • 使用 API 解决 reCAPTCHA v2:分步实战指南
  • 如何使用 API 解决 Cloudflare Turnstile
  • 如何使用 API 解决 GeeTest v3 问题
该文章已禁用评论。