Solución de Problemas

El CAPTCHA de automatización del navegador falla pero la API funciona: guía de depuración

Resolvió el CAPTCHA a través de CaptchaAI y obtuvo un token válido, pero inyectarlo en el navegador no funciona. Esta guía cubre todos los motivos y cómo solucionar cada uno de ellos.


Puntos de falla comunes

Problema Síntoma Causa raíz
Token no inyectado en el elemento correcto El formulario se envía sin token Selector de área de texto incorrecto
El token expiró antes del envío El sitio muestra CAPTCHA nuevamente Demasiado lento entre resolver y enviar
Callback no activado El botón de formulario permanece deshabilitado Falta el callback de grecaptcha
URL de página incorrecta enviada a la API Token no válido para este dominio La URL no coincide
Detección de bots más allá de CAPTCHA Bloqueado después de aceptar el token Fingerprinting del navegador

Solución 1: Inyección de token correcta para reCAPTCHA v2

El token debe ir al área de texto g-recaptcha-response Y el callback debe activarse:

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()

Solución 2: Manejar formularios dependientes de callback

Algunos formularios permanecen deshabilitados hasta que se activa el callback CAPTCHA:

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

Solución 3: sincronización: solución y uso inmediato

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")

Solución 4: URL de página correcta para SPA e Iframes

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)

Solución 5: Detección anti-bot más allá de CAPTCHA

Incluso con un token válido, el sitio puede bloquear navegadores automatizados:

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


def create_driver():
    """Create a Chrome browser instance for testing."""
    options = Options()

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

    driver = webdriver.Chrome(options=options)
    return driver


driver = create_driver()

Solución 6: inyección de fichas de torniquete

Cloudflare Turnstile utiliza un enfoque de inyección diferente:

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)

Lista de verificación de depuración

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

Solución de problemas

Síntoma Causa Solución
Token inyectado pero el formulario se rechaza Callback no activado Localiza y llama a la función callback
El botón Enviar permanece deshabilitado El callback lo habilita Activa el callback tras inyectar el token
"CAPTCHA no válido" después del envío Token caducado Reduce el tiempo entre resolución y envío
403 después del envío del formulario Detección de bots (no CAPTCHA) Usa opciones headless con flags adecuados
Funciona en requests, falla en el navegador URL de página diferente Usa driver.current_url como pageUrl

Preguntas frecuentes

¿Por qué el token funciona en requests pero no en el navegador?

Generalmente porque el callback no se activa. Los formularios del navegador a menudo dependen del callback para habilitar el envío o establecer campos ocultos.

¿Necesito usar un navegador específico?

Chrome/Chromium es el más compatible. Firefox funciona pero puede requerir enfoques diferentes para los comandos CDP. Usa undetected-chromedriver en sitios con detección de bots fuerte.

¿Debería usar el modo headless?

Algunos sitios detectan navegadores headless y rechazan tokens. Prueba primero en modo headed; si funciona, cambia a headless con los flags adecuados.


Guías relacionadas

  • Cloudflare Turnstile 403 después del token: solución
  • Inicio rápido de CaptchaAI
  • Cómo resolver reCAPTCHA v2 con la API
Los comentarios están deshabilitados para este artículo.