Token de captcha caducado: causas y cómo solucionarlo
Un token de captcha es una prueba de corta duración de que se superó un desafío. Los tokens de PopularCaptcha de Scarnox caducan unos dos minutos después de emitirse. Si envías un token después de esa ventana, el sitio rechaza el formulario, a menudo con un mensaje que dice que el captcha ha caducado o no es válido. La solución casi siempre tiene que ver con el momento: resuelve el captcha lo más cerca posible del envío, usa cada token una sola vez y reintenta solo cuando sepas que el primer intento no fue aceptado.
Por qué caducan los tokens
Un token no es una credencial permanente. El sitio quiere saber que una persona (o un solver que actúa en su nombre) completó el desafío hace poco, así que le da una vida corta. El reloj empieza cuando se emite el token, no cuando llamas por primera vez a la API. Todo lo que pasa entre la resolución y el envío consume esos dos minutos.
Causas habituales
- Resolver demasiado pronto. Pre-resolver un lote de tokens y guardarlos para más tarde es la causa más frecuente. Cuando se usa un token, ya está caducado.
- Código lento entre la resolución y el envío. Una escritura larga en la base de datos, una cola o un
time.sleepcolocado antes del POST del formulario pueden llevar el token fuera de su ventana. - Reutilizar un token. Un token que ya fue aceptado, o que un intento fallido ya usó, no volverá a funcionar. Trata cada token como de un solo uso.
- Recargar la página. Si la página se refresca después de la resolución, el formulario puede generar un nuevo desafío y invalidar el token que tienes.
La solución: resuelve justo antes de enviar
El patrón más sencillo y fiable es hacer de la resolución y el envío un único paso. Pide un token, ponlo en el formulario, envía el formulario y no hagas nada lento entre medias:
import requests
API_KEY = "scarnox_YOURAPIKEY"
CREATE_URL = "https://api.scarnox.com/api/tasks/create"
def fresh_token(sitekey: str, page_url: str) -> str:
r = requests.post(
CREATE_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185, # the call blocks until the token is ready
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
def submit_form(page_url: str, sitekey: str, form: dict) -> requests.Response:
token = fresh_token(sitekey, page_url) # solve right before posting
return requests.post(
page_url,
data={**form, "h-captcha-response": token, "g-recaptcha-response": token},
timeout=30,
)
Fíjate en que submit_form no guarda un token en una caché ni en una cola. Pide uno, lo envía y sigue. Las resoluciones fallidas no se cobran, así que una petición fallida no te cuesta nada en el lado de la resolución.
Reintenta con seguridad
Algunos sitios rechazan un token caducado con una respuesta clara. Otros devuelven una página normal con un mensaje de error dentro, así que el código de estado por sí solo no te dirá nada. Mira la respuesta que el sitio devuelve de verdad para un token caducado y construye tu comprobación en torno a ella. Un bucle de reintentos podría verse así:
def submit_with_retry(page_url: str, sitekey: str, form: dict, attempts: int = 2):
for _ in range(attempts):
resp = submit_form(page_url, sitekey, form)
if resp.status_code < 400 and "captcha" not in resp.text.lower():
return resp # accepted, as far as this site's response shows
raise RuntimeError("captcha token rejected after retries")
Ten cuidado con los reintentos en formularios que crean algo. Si el primer intento sí fue aceptado pero tu código interpretó mal la respuesta, un reintento puede crear una cuenta, un pedido o un mensaje duplicado. Reintenta solo cuando estés seguro de que el primer envío no fue aceptado, y haz que la comprobación sea específica del sitio con el que trabajas.
Mantén el tiempo honesto
- No resuelvas en un bucle de tokens que pienses usar más tarde. Resuelve por cada envío.
- Mantén el trabajo entre la resolución y el POST al mínimo.
- Usa un timeout de unos 185 segundos en la petición de resolución, porque la llamada se bloquea hasta que el token está listo. Un temporizador aparte para tu propio envío del formulario debe ser mucho más corto que la vida del token.
- Si necesitas un pipeline más rápido, consulta velocidad de resolución de captchas, que cubre las resoluciones en paralelo sin guardar tokens.
Errores habituales
- Guardar tokens en un diccionario o en Redis para usarlos después. La caché parece inofensiva hasta que se usa un token fuera de su ventana y todos los envíos fallan.
- Resolver una vez por sesión. Una sesión de larga duración sigue necesitando un token nuevo para cada envío del formulario, porque cada envío puede ejecutar su propia comprobación del desafío.
- Esperar entre la resolución y el envío. Un limitador de frecuencia o una pausa deliberada colocada después de la resolución consume la vida del token. Pon cualquier control de ritmo antes de la resolución.
- Tratar todos los fallos por igual. Un timeout de tu lado, un token rechazado y un error del sitio necesitan gestiones distintas. Regístralos por separado.
Registra lo suficiente para diagnosticarlo
Cuando un envío falla, anota la hora en que se emitió el token, la hora en que se envió el formulario, el código HTTP y los primeros cientos de caracteres de la respuesta. Con esos cuatro valores puedes ver de un vistazo si el token caducó o si el sitio lo rechazó por otro motivo. No registres el token completo en logs compartidos, porque un token válido es una credencial para ese único desafío.
Qué comprobar si sigue fallando
- Imprime el tiempo transcurrido entre la devolución del token y el POST del formulario.
- Confirma que
site_urlcoincide con la página que muestra el captcha. - Confirma que la sitekey se leyó de la página actual, no de una copia antigua.
- Confirma los nombres de los campos del formulario. Los tokens de PopularCaptcha van en
h-captcha-response, y a menudo también eng-recaptcha-response.
Para la lista completa de respuestas de error y cómo gestionar cada una, consulta gestión de errores del solver de captchas.