Integraciones

Resolver CAPTCHA con undetected-chromedriver y CaptchaAI

Cuando automatizas Chrome con Selenium y el sitio te responde con un reCAPTCHA o un Cloudflare Turnstile, en realidad tienes dos problemas distintos: reducir las señales que delatan la automatización y resolver el CAPTCHA que aparece de todos modos. undetected-chromedriver se ocupa de lo primero; CaptchaAI, de lo segundo.

undetected-chromedriver (UC) es una biblioteca de Python que ajusta el ChromeDriver de Selenium: elimina algunas marcas de automatización y mantiene la compatibilidad de versiones entre Chrome y su controlador. Con eso aparecen menos CAPTCHA, pero no desaparecen; cuando el sitio insiste, CaptchaAI lo resuelve por API y devuelve un token que inyectas en la página. Esta guía encadena ambas piezas en un flujo real de Selenium: montar el navegador, extraer el sitekey, resolver con CaptchaAI e inyectar el token.


Por qué necesitas las dos herramientas

Un navegador con menos señales de automatización no deja de ver CAPTCHA. La detección combina reputación de la IP, comportamiento del ratón, cabeceras HTTP e historial de sesión, así que un reCAPTCHA v2 o un Turnstile puede activarse con una configuración limpia. Por eso conviene dividir responsabilidades:

  • UC gestiona el navegador: mantiene ChromeDriver al día y ajusta las señales que revisan los sitios.
  • CaptchaAI resuelve el desafío: recibe el sitekey y la URL, resuelve el CAPTCHA y devuelve el token listo para inyectar.

Separar ambas capas da una tasa de éxito alta y estable: cada herramienta hace solo lo que sabe hacer.


Lo que vas a necesitar

Requisito Detalles
Clave API CaptchaAI captchaai.com
Python 3.8+
Navegador Chrome Instalado en tu sistema

Instala las dependencias:

pip install undetected-chromedriver requests

Configuración básica del navegador

Arranca una instancia de Chrome con UC. Los argumentos --no-sandbox y --window-size cubren la mayoría de los entornos de servidor y contenedores:

import undetected_chromedriver as uc
import requests
import time


def create_browser():
    """Create a Chrome browser instance."""
    options = uc.ChromeOptions()
    options.add_argument("--no-sandbox")
    options.add_argument("--window-size=1920,1080")

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

Dos apuntes sobre las opciones:

  • --no-sandbox evita fallos de permisos en contenedores y servidores.
  • --window-size=1920,1080 fija una ventana de escritorio típica.

Resolver reCAPTCHA v2 paso a paso

El flujo tiene tres pasos y conviene respetarlos en orden:

  1. Localiza el sitekey en la página.
  2. Pide el token a CaptchaAI y espera la resolución.
  3. Inyecta el token y envía el formulario.

Paso 1: localiza el sitekey en la página

El sitekey suele estar en el atributo data-sitekey; si no, se extrae del src del iframe de reCAPTCHA:

API_KEY = "YOUR_API_KEY"


def extract_recaptcha_sitekey(driver):
    """Extract reCAPTCHA v2 sitekey from the page."""
    try:
        element = driver.find_element("css selector", "[data-sitekey]")
        return element.get_attribute("data-sitekey")
    except Exception:
        # Try finding in iframe src
        iframes = driver.find_elements("css selector", "iframe[src*='recaptcha']")
        for iframe in iframes:
            src = iframe.get_attribute("src")
            if "k=" in src:
                return src.split("k=")[1].split("&")[0]
    return None

Paso 2: resuelve el CAPTCHA con CaptchaAI

Envía la tarea al endpoint in.php con el método userrecaptcha y consulta el resultado en res.php hasta que el token esté listo. El primer time.sleep(20) da margen antes de sondear:

def solve_recaptcha_v2(sitekey, pageurl):
    """Submit reCAPTCHA v2 to CaptchaAI and return the token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]

    time.sleep(20)
    for _ in range(30):
        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 RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)

    raise TimeoutError("Solve timed out")

Paso 3: inyecta el token y envía el formulario

Con el token en la mano, escríbelo en el campo g-recaptcha-response y, si la página usa una función de callback, dispárala para que registre la resolución:

def inject_recaptcha_token(driver, token):
    """Inject the solved token into the page and submit."""
    driver.execute_script(f'''
        document.getElementById("g-recaptcha-response").innerHTML = "{token}";
        document.getElementById("g-recaptcha-response").style.display = "block";
    ''')

    # If there's a callback function, trigger it
    driver.execute_script(f'''
        if (typeof ___grecaptcha_cfg !== 'undefined') {{
            var clients = ___grecaptcha_cfg.clients;
            for (var key in clients) {{
                var client = clients[key];
                if (client && client.callback) {{
                    client.callback("{token}");
                }}
            }}
        }}
    ''')

Flujo completo: iniciar sesión con reCAPTCHA

Este ejemplo une todo: abre un login de pruebas, rellena las credenciales, extrae el sitekey, resuelve con CaptchaAI, inyecta el token y envía el formulario. El try/finally cierra el navegador aunque algo falle:

import undetected_chromedriver as uc
import requests
import time

API_KEY = "YOUR_API_KEY"


def solve_recaptcha(sitekey, pageurl):
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY, "method": "userrecaptcha",
        "googlekey": sitekey, "pageurl": pageurl, "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    time.sleep(20)

    for _ in range(30):
        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 RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")


def main():
    driver = uc.Chrome()

    try:
        # Navigate to target page
        driver.get("https://staging.example.com/qa-login")
        time.sleep(3)

        # Fill in form fields
        driver.find_element("id", "username").send_keys("user")
        driver.find_element("id", "password").send_keys("pass")

        # Extract sitekey
        element = driver.find_element("css selector", "[data-sitekey]")
        sitekey = element.get_attribute("data-sitekey")
        pageurl = driver.current_url
        print(f"Sitekey: {sitekey}")

        # Solve CAPTCHA
        token = solve_recaptcha(sitekey, pageurl)
        print(f"Token: {token[:50]}...")

        # Inject token
        driver.execute_script(
            f'document.getElementById("g-recaptcha-response").innerHTML = "{token}";'
        )

        # Submit form
        driver.find_element("id", "submit-btn").click()
        time.sleep(3)

        print(f"Current URL: {driver.current_url}")
    finally:
        driver.quit()


if __name__ == "__main__":
    main()

Trabaja siempre contra un entorno propio (staging.example.com/qa-login en el ejemplo) y respeta los términos de servicio y la normativa de datos aplicable (GDPR, LOPDGDD, LFPDPPP).


Resolver Cloudflare Turnstile

El patrón es idéntico al de reCAPTCHA; solo cambian dos detalles:

  • El método pasa de userrecaptcha a turnstile.
  • El campo del token pasa de g-recaptcha-response a cf-turnstile-response.

Extrae el sitekey y resuelve así:

def solve_turnstile(sitekey, pageurl):
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY, "method": "turnstile",
        "sitekey": sitekey, "pageurl": pageurl, "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    time.sleep(10)

    for _ in range(30):
        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 RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")


# Inject Turnstile token
def inject_turnstile_token(driver, token):
    driver.execute_script(f'''
        var input = document.querySelector('[name="cf-turnstile-response"]');
        if (input) input.value = "{token}";
    ''')

Un caso real: QA de un portal con cita previa

Un escenario habitual en el mercado hispanohablante son los portales públicos protegidos con CAPTCHA: los centros de visado BLS que atienden a solicitantes de toda Latinoamérica, las páginas de cita previa en España o los trámites del SAT en México. Si tu equipo mantiene un panel que verifica periódicamente que uno de esos formularios sigue funcionando —siempre sobre flujos autorizados—, UC mantiene la sesión estable y CaptchaAI resuelve el reCAPTCHA del envío. El mismo patrón sirve para monitorizar precios en marketplaces como MercadoLibre o Amazon.es, como tarea de QA, no de compra automatizada.


Qué plan de CaptchaAI elegir

CaptchaAI se factura por thread concurrente, no por CAPTCHA resuelto: un thread es un desafío en curso y, en cuanto termina, queda libre para el siguiente. Todos los planes incluyen resoluciones ilimitadas dentro del mes.

  • BASIC — $15/mes, 5 threads. Suficiente para un scraper o una suite de pruebas de un proceso.
  • STANDARD — $30/mes, 15 threads. Buen punto de partida con varios workers en paralelo.
  • ADVANCE — $90/mes, 50 threads, y por encima PREMIUM ($170/mes, 100 threads) para volúmenes altos.

Para agencias que facturan en monedas locales volátiles, un costo mensual predecible en USD es más fácil de presupuestar que el pago por resolución.


Solución de problemas frecuentes

Problema Causa Solución
La versión de Chrome no coincide UC no encuentra el controlador correspondiente Actualiza Chrome o especifica version_main en uc.Chrome()
El CAPTCHA sigue apareciendo El sitio activa el desafío pese a UC Es lo esperado: deja que CaptchaAI lo resuelva automáticamente
Falla la inyección del token ID de elemento incorrecto o falta el callback Revisa la implementación de reCAPTCHA de la página
WebDriverException Chrome se cerró de forma inesperada Añade --no-sandbox y --disable-dev-shm-usage

Preguntas frecuentes

¿Necesito undetected-chromedriver si ya uso CaptchaAI?

No es obligatorio, pero ayuda. CaptchaAI resuelve el CAPTCHA venga de donde venga, así que puedes usarlo con Selenium estándar. UC reduce la cantidad de desafíos que se disparan, con lo que gastas menos resoluciones.

¿Cada cuánto cambia el sitekey de una página?

El sitekey es estable: pertenece al sitio y no rota por sesión. Conviene extraerlo en tiempo de ejecución en lugar de fijarlo en el código, así tu script sigue funcionando si el sitio lo actualiza.

¿Cuánto tarda CaptchaAI en devolver el token?

Normalmente unos pocos segundos. Por eso el código espera un margen inicial (time.sleep) y luego sondea res.php cada cinco segundos hasta que el token esté listo o se agote el tiempo.

¿Puedo resolver varios CAPTCHA a la vez?

Sí. Como la facturación es por thread concurrente, el número de resoluciones simultáneas lo marca tu plan: 5 threads en BASIC, 15 en STANDARD, y así sucesivamente. Lanza tus workers en paralelo hasta ese límite.

Depende del uso. Resolver CAPTCHA para automatizar o hacer QA de flujos que controlas o tienes autorización para usar es legítimo; hacerlo sobre servicios de terceros sin permiso puede violar sus términos. Revisa siempre las condiciones del sitio y la normativa aplicable.


Empieza a resolver CAPTCHA en tu automatización

Obtén tu clave API en captchaai.com y combina la automatización del navegador con una resolución de CAPTCHA fiable. Con UC delante y CaptchaAI detrás, tu pipeline de Selenium deja de detenerse cuando aparece un reCAPTCHA o un Turnstile.


Guías relacionadas

Los comentarios están deshabilitados para este artículo.