Cómo resolver un PopularCaptcha en Python (ejemplo práctico, 2026)
Si tu script de Python se ha topado con un PopularCaptcha, no necesitas una granja de navegadores ni un modelo propio. Necesitas la sitekey de la página, una petición POST y el token que devuelve.
Esta guía te lleva de cero a un token válido en unos cinco minutos: obtener una clave de API, encontrar la sitekey, pedir el token, enviarlo al formulario y gestionar los casos de fallo que aparecen cuando un script se ejecuta sin supervisión. Las resoluciones fallidas son gratuitas, así que un reintento solo te cuesta tiempo.
Scarnox resuelve PopularCaptcha hoy, con proxy o sin él. Otros tipos de captcha como reCAPTCHA, Cloudflare Turnstile y AWS WAF llegarán pronto, así que todos los ejemplos de aquí usan PopularCaptcha. El resumen de tipos de captcha explica en qué se diferencian los demás.
1. Obtén una clave de API
Crea una cuenta y empieza con crédito de prueba gratis, sin tarjeta. Tu clave de API está en el panel. No la guardes en el código fuente: léela de una variable de entorno:
export SCARNOX_KEY="scarnox_YOURAPIKEY"
2. Encuentra la sitekey
Abre la página con el captcha, abre DevTools y busca data-sitekey en el panel Elements. Las sitekeys de PopularCaptcha son UUID:
<div class="h-captcha" data-sitekey="10000000-ffff-ffff-ffff-000000000001"></div>
¿No hay data-sitekey en el HTML? Lo más probable es que el widget lo renderice JavaScript. Revisa en la pestaña Network la petición de configuración del widget; su parámetro de consulta sitekey es el que necesitas. Otras formas de encontrarla cubren la URL del iframe y los widgets invisibles.
Envía como site_url la URL de la página que muestra el widget. El host es lo más importante, pero la URL completa de la página es la opción segura.
3. Pide un token
import os
import requests
API_URL = "https://api.scarnox.com/api/tasks/create"
API_KEY = os.environ["SCARNOX_KEY"]
def solve_captcha(sitekey: str, page_url: str) -> str:
r = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185, # la llamada se bloquea hasta que el token está listo
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
if __name__ == "__main__":
token = solve_captcha("10000000-ffff-ffff-ffff-000000000001", "https://example.com/signup")
print(token[:40], "...")
Eso es toda la integración. No hay bucle de sondeo ni una segunda llamada de "obtener resultado". La petición devuelve el control cuando el token está listo, así que el único ajuste que importa es un timeout lo bastante largo para cubrir una resolución lenta. Usa unos 185 segundos.
Una respuesta correcta tiene errorId con valor 0, y el token bajo solution.token. Cualquier otro errorId significa que la resolución falló, y la respuesta trae un errorCode y un errorDescription que explican por qué.
4. Envía el token
El token va donde el sitio espera la respuesta del captcha. En PopularCaptcha, casi siempre es un campo de formulario llamado h-captcha-response. Muchos sitios aceptan también g-recaptcha-response, así que envía los dos:
import requests
def sign_up(session: requests.Session, form_url: str, email: str, sitekey: str) -> requests.Response:
token = solve_captcha(sitekey, form_url)
return session.post(form_url, data={
"email": email,
"h-captcha-response": token,
"g-recaptcha-response": token,
}, timeout=30)
Dos detalles importan aquí. Los sitios reales suelen comprobar también las cookies de sesión de la carga de la página, así que carga el formulario con el mismo requests.Session antes de enviar el POST. Y envía el POST a la action del formulario, que no siempre es la URL de la página.
Resuelve justo antes de enviar. El token caduca en unos dos minutos, así que no lo pidas al inicio de un trabajo largo y lo guardes. Si el sitio rechaza el token, abre el formulario en DevTools y confirma los nombres de los campos ocultos.
5. Gestiona los fallos
Las resoluciones fallidas son gratuitas, así que un reintento solo cuesta tiempo. Pero algunos errores nunca se resolverán con un reintento, así que no reintentes a ciegas. Comprueba errorId siempre, registra errorCode y errorDescription, y reintenta solo los fallos transitorios.
Los errores de red necesitan su propio tratamiento, porque requests lanza una excepción antes de que exista cualquier respuesta:
import requests
try:
token = solve_captcha(sitekey, page_url)
except requests.RequestException as exc:
print("network problem, retry later:", exc)
except RuntimeError as exc:
print("solve rejected:", exc)
La guía de gestión de errores tiene una política de reintentos completa, con retroceso y variación aleatoria.
Errores comunes
- **
site_urlincorrecta.** Envía la página que muestra el widget, no la página de inicio. - Token caducado. Un token usado después de unos dos minutos se rechaza. Resuelve justo antes de enviar.
- Sesión que falta. Un POST sin las cookies de la página puede fallar aunque el token sea válido.
- **Algunos sitios necesitan
rqdata.** Si la página aporta un valorrqdatapara el widget, envíalo en la petición en el campo opcionalrqdata. - Widget invisible. Si no hay casilla y el sitio inicia el widget desde su propio código, añade
"is_invisible": truea la petición. La guía de captcha invisible explica cómo devolver el token.
Pruébalo gratis
Crea una cuenta y empieza con crédito de prueba gratis, sin tarjeta. Ejecuta el ejemplo de arriba contra un formulario que sea tuyo antes de integrarlo en un trabajo más grande. Para saber cuánto cuesta resolver a gran volumen, consulta las tarifas actuales.
Registro de cada resolución
Registra una línea por resolución: la sitekey, el host de la página, el errorId, el errorCode si falla y cuánto tardó la llamada. No incluyas la clave de API ni la contraseña de ningún proxy. Estas líneas te dicen si una ejecución lenta es lenta por la página, por el proxy o por el solver. También son lo primero que necesitarás si abres una solicitud de soporte.
Resolver en un bucle
Si tu script resuelve muchos captchas seguidos, mantén el bucle sencillo. Resuelve, envía, comprueba el resultado y solo entonces pasa al siguiente. No resuelvas por adelantado ni pongas tokens en cola, porque cada uno caduca en unos dos minutos. Una pausa corta entre resoluciones en el mismo sitio mantiene tu ritmo de peticiones cerca del que produciría una persona.