Token de captcha expiré : causes et solutions
Un token de captcha est une preuve de courte durée qu'un défi a été réussi. Les tokens PopularCaptcha de Scarnox expirent environ deux minutes après leur émission. Si vous soumettez un token après cette fenêtre, le site rejette le formulaire, souvent avec un message indiquant que le captcha a expiré ou est invalide. La correction concerne presque toujours le timing : résolvez le captcha au plus près de la soumission, utilisez chaque token une seule fois, et ne réessayez que lorsque vous savez que la première tentative n'a pas été acceptée.
Pourquoi les tokens expirent
Un token n'est pas un identifiant permanent. Le site veut savoir qu'une personne (ou un solveur agissant pour elle) a accompli le défi récemment, il donne donc au token une courte durée de vie. Le chronomètre démarre à l'émission du token, et non au moment où vous appelez l'API pour la première fois. Tout ce qui se passe entre la résolution et la soumission consomme ces deux minutes.
Causes courantes
- Résoudre trop tôt. Pré-résoudre un lot de tokens et les garder pour plus tard est la cause la plus fréquente. Au moment où un token est utilisé, il est périmé.
- Code lent entre la résolution et la soumission. Une longue écriture en base de données, une file d'attente ou un
time.sleepplacé avant l'envoi du formulaire peut faire dépasser la fenêtre au token. - Réutiliser un token. Un token déjà accepté, ou déjà utilisé par une tentative échouée, ne fonctionnera plus. Considérez chaque token comme à usage unique.
- Recharger la page. Si la page est rafraîchie après la résolution, le formulaire peut émettre un nouveau défi et invalider le token que vous détenez.
La solution : résoudre juste avant de soumettre
Le schéma le plus simple et le plus fiable consiste à faire de la résolution et de la soumission une seule étape. Demandez un token, placez-le dans le formulaire, envoyez le formulaire, et ne faites rien de lent entre les deux :
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, # l'appel bloque jusqu'à ce que le token soit prêt
)
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) # résoudre juste avant l'envoi
return requests.post(
page_url,
data={**form, "h-captcha-response": token, "g-recaptcha-response": token},
timeout=30,
)
Remarquez que submit_form ne garde aucun token dans un cache ou une file d'attente. Il en demande un, l'envoie, et passe à la suite. Les résolutions échouées ne sont pas facturées, donc une requête échouée ne vous coûte rien côté résolution.
Réessayer en toute sécurité
Certains sites rejettent un token expiré avec une réponse claire. D'autres renvoient une page normale contenant un message d'erreur, si bien qu'un code de statut seul ne suffit pas à le savoir. Regardez la réponse que le site renvoie réellement pour un token expiré, et construisez votre contrôle à partir de celle-ci. Une boucle de réessai pourrait ressembler à ceci :
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 # accepté, d'après la réponse de ce site
raise RuntimeError("captcha token rejected after retries")
Soyez prudent avec les réessais sur les formulaires qui créent quelque chose. Si la première tentative a bel et bien été acceptée mais que votre code a mal interprété la réponse, un réessai peut créer un compte, une commande ou un message en double. Ne réessayez que lorsque vous êtes certain que le premier envoi n'a pas été accepté, et rendez le contrôle spécifique au site sur lequel vous travaillez.
Gardez un timing honnête
- Ne résolvez pas en boucle des tokens que vous comptez utiliser plus tard. Résolvez à chaque soumission.
- Gardez le travail entre la résolution et l'envoi au minimum.
- Utilisez un délai d'environ 185 secondes sur la requête de résolution, car l'appel bloque jusqu'à ce que le token soit prêt. Un minuteur distinct sur votre propre envoi de formulaire doit être bien plus court que la durée de vie du token.
- Si vous avez besoin d'un pipeline plus rapide, consultez la vitesse de résolution des captchas, qui couvre les résolutions parallèles sans stocker de tokens.
Erreurs courantes
- Mettre les tokens en cache dans un dictionnaire ou Redis pour plus tard. Le cache paraît inoffensif jusqu'au moment où un token est utilisé après sa fenêtre et où chaque soumission échoue.
- Résoudre une fois par session. Une session de longue durée a toujours besoin d'un nouveau token pour chaque envoi de formulaire, car chaque envoi peut déclencher sa propre vérification de défi.
- Dormir entre la résolution et la soumission. Un limiteur de débit ou une pause volontaire placé après la résolution consomme la durée de vie du token. Placez plutôt tout cadencement avant la résolution.
- Traiter toutes les erreurs de la même façon. Un dépassement de délai de votre côté, un token rejeté et une erreur du site demandent des traitements différents. Journalisez-les séparément.
Journalisez assez pour diagnostiquer
Lorsqu'une soumission échoue, notez l'heure d'émission du token, l'heure d'envoi du formulaire, le statut HTTP et les premières centaines de caractères de la réponse. Avec ces quatre valeurs, vous voyez d'un coup d'œil si le token a expiré ou si le site l'a rejeté pour une autre raison. Ne journalisez pas le token complet dans des journaux partagés, car un token valide est un identifiant pour ce défi précis.
Que vérifier si cela échoue encore
- Affichez le temps écoulé entre le retour du token et l'envoi du formulaire.
- Confirmez que
site_urlcorrespond à la page qui affiche le captcha. - Confirmez que la sitekey a été lue sur la page actuelle, et non sur une copie ancienne.
- Confirmez les noms des champs du formulaire. Les tokens PopularCaptcha vont dans
h-captcha-response, et souvent aussi dansg-recaptcha-response.
Pour la liste complète des réponses d'erreur et la façon de traiter chacune, consultez la gestion des erreurs du solveur de captcha.