Solução de Problemas

Expiração do token reCAPTCHA: janelas de tempo e condições de corrida

O erro timeout-or-duplicate é a falha reCAPTCHA mais comum em fluxos de trabalho de automação. Isso significa que seu token expirou antes do envio ou foi usado duas vezes. Com os tokens reCAPTCHA durando apenas 120 segundos e os solucionadores de API levando de 15 a 45 segundos para gerá-los, o gerenciamento do tempo é fundamental. Este guia aborda a mecânica exata de expiração, condições comuns de corrida e estratégias práticas de tempo.


A regra dos 120 segundos

Cada token reCAPTCHA expira exatamente 120 segundos após a geração. Isso se aplica a todas as versões:

Token generated (solve complete)
    ├─── 0s:   Token is valid ✓
    ├─── 60s:  Token is valid ✓
    ├─── 110s: Token is valid ✓  (but cutting it close)
    ├─── 119s: Token is valid ✓  (dangerous territory)
    └─── 120s: Token EXPIRED ✗  (timeout-or-duplicate)

Onde o cronômetro começa

Cenário O cronômetro inicia quando...
Caixa de seleção reCAPTCHA v2 O usuário marca a caixa de seleção (desafio resolvido)
Grade de imagem reCAPTCHA v2 O usuário conclui a rodada final de seleção de imagens
reCAPTCHA v2 invisível O retorno de chamada execute() é acionado com token
reCAPTCHA v3 execute() Promise resolve com token
Solucionador de API (CaptchaAI) O Solver gera o token (NÃO quando você o recebe)

A lacuna de tempo do solucionador

Ao usar um solucionador de API, há um atraso entre o momento em que o solucionador gera o token e o momento em que seu código o recebe:

Solver generates token (timer starts)
    ↓ ~1-5 seconds (network + polling interval)
Your code receives token via res.php poll
    ↓ You now have ~115-119 seconds remaining
Your code processes and submits token
    ↓ ~1-10 seconds (depends on your workflow)
Target website validates token with Google
    ↓ ~1-2 seconds (Google API response time)
Total remaining after validation: ~105-117 seconds (comfortable)

Na prática, a janela de 120 segundos oferece tempo suficiente para o envio do seu código imediatamente após o recebimento do token. Os problemas ocorrem quando:

  • Seu código tem etapas de processamento adicionais entre o recebimento do token e o envio dele
  • Vários formulários precisam ser preenchidos antes do envio
  • O site de destino tem um tempo de resposta lento
  • Você enfileira tokens e os envia mais tarde

Condições comuns de corrida

Condição de corrida 1: resolução paralela + envio sequencial

# WRONG: Solving multiple CAPTCHAs in parallel, then submitting sequentially
tokens = []
for url in urls:
    task_id = solve_captcha(url)  # All submitted at t=0
    tokens.append(task_id)

# All tokens arrive around t=30
solved_tokens = [poll_result(tid) for tid in tokens]

# Sequential submission: first token at t=32, last at t=120+
for i, (url, token) in enumerate(zip(urls, solved_tokens)):
    submit_form(url, token)  # Later tokens may be expired!
    time.sleep(10)  # Each wait adds pressure

Correção: Resolva e envie cada CAPTCHA antes de iniciar o próximo:

# CORRECT: Solve and submit one at a time
for url in urls:
    token = solve_and_wait(url)  # Token received at t=30
    submit_form(url, token)      # Submitted at t=31 (89 seconds remaining)

Condição de corrida 2: pré-busca de token

# WRONG: Pre-fetching tokens before knowing when they'll be used
token = solve_captcha()  # Token received at t=0

# ... user fills out form (30-120+ seconds) ...
# ... validation checks ...
# ... other processing ...

submit_form(token)  # Token may be expired!

Correção: Resolva o CAPTCHA como última etapa antes do envio:

# CORRECT: Late-bind the CAPTCHA solve
prepare_form_data()   # Do everything that doesn't need the token
validate_inputs()     # Run validation before spending a token

# Now solve and submit immediately
token = solve_captcha()  # Token received at t=0
submit_form(token)       # Submitted at t=1 (119 seconds remaining)

Condição de corrida 3: envio de formulário em várias etapas

# PROBLEMATIC: Multi-step form where CAPTCHA is on step 1 but submit is step 3
token = solve_captcha()       # t=0: Token received

fill_step_1(token)            # t=5: Step 1 submitted
response = fill_step_2()      # t=15: Step 2 completed
# ... step 2 has additional verification ...
wait_for_verification()       # t=60: Verification complete
fill_step_3_and_submit()      # t=65: Final submission (55 seconds remaining - OK)
# BUT if step 2 takes longer than expected...

Correção: Meça a idade do token e resolva se necessário:

token_received_at = time.time()
token = solve_captcha()
token_received_at = time.time()

# ... multi-step process ...

# Before final submission, check token age
token_age = time.time() - token_received_at
if token_age > 100:  # 20-second safety margin
    print(f"Token is {token_age:.0f}s old — requesting fresh token")
    token = solve_captcha()
    token_received_at = time.time()

submit_final(token)

Gerenciador de tempo de token

Uma classe pronta para produção para gerenciar a vida útil do token:

import time
import requests

class TokenTimingManager:
    """Manage reCAPTCHA token timing to prevent expiration errors."""

    API_KEY = "YOUR_API_KEY"
    TOKEN_LIFETIME = 120
    SAFETY_MARGIN = 15  # seconds before expiry to consider "stale"

    def __init__(self, site_key, page_url, version="v2"):
        self.site_key = site_key
        self.page_url = page_url
        self.version = version
        self.current_token = None
        self.token_timestamp = None

    def _solve(self):
        """Request and poll for a new token."""
        params = {
            "key": self.API_KEY,
            "method": "userrecaptcha",
            "googlekey": self.site_key,
            "pageurl": self.page_url,
            "json": 1,
        }
        if self.version == "v3":
            params.update({"version": "v3", "action": "submit", "score_qa": "0.9"})

        submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()
        task_id = submit["request"]

        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.API_KEY,
                "action": "get",
                "id": task_id,
                "json": 1,
            }).json()

            if result.get("status") == 1:
                self.current_token = result["request"]
                self.token_timestamp = time.time()
                return self.current_token

        raise TimeoutError("Token solve timeout")

    @property
    def token_age(self):
        """Seconds since current token was received."""
        if self.token_timestamp is None:
            return float("inf")
        return time.time() - self.token_timestamp

    @property
    def token_remaining(self):
        """Seconds remaining before token expires."""
        return max(0, self.TOKEN_LIFETIME - self.token_age)

    @property
    def is_fresh(self):
        """Whether the token is fresh enough to use."""
        return self.token_remaining > self.SAFETY_MARGIN

    def get_token(self):
        """Get a valid token, solving if current is stale or missing."""
        if self.current_token and self.is_fresh:
            return self.current_token

        return self._solve()

    def use_token(self):
        """Get and consume a token (cannot be reused)."""
        token = self.get_token()
        # Mark as consumed
        self.current_token = None
        self.token_timestamp = None
        return token


# Usage
manager = TokenTimingManager(
    site_key="6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
    page_url="https://staging.example.com/qa-login",
)

# Get a fresh token right before submission
token = manager.use_token()
print(f"Token remaining: {manager.TOKEN_LIFETIME}s (fresh solve)")

# Submit form with token...

Lidando com o erro de tempo limite ou duplicado

Ao receber timeout-or-duplicate, diagnostique a causa:

def handle_recaptcha_error(error_codes, token_age_seconds):
    """Diagnose and handle reCAPTCHA validation errors."""

    if "timeout-or-duplicate" in error_codes:
        if token_age_seconds > 120:
            return {
                "cause": "Token expired (age: {:.0f}s > 120s)".format(token_age_seconds),
                "fix": "Reduce time between receiving and submitting token",
                "action": "re-solve",
            }
        elif token_age_seconds < 5:
            return {
                "cause": "Token likely reused (duplicate submission)",
                "fix": "Ensure each form submission gets a unique token",
                "action": "re-solve",
            }
        else:
            return {
                "cause": "Token may have been reused or server-side timing issue",
                "fix": "Check for double-submit in form handler",
                "action": "re-solve",
            }

    if "invalid-input-response" in error_codes:
        return {
            "cause": "Token is malformed or corrupted",
            "fix": "Check token transmission (URL encoding, field name)",
            "action": "re-solve",
        }

    return {"cause": "Unknown", "action": "investigate"}

Práticas recomendadas de tempo

Pratique Recomendação
Lacuna entre resolver e enviar Mantenha menos de 90 segundos (margem de 30 segundos)
Intervalo da pesquisa 5 segundos entre verificações res.php
validação antecipada em staging Somente pré-resolva se você souber que o envio acontecerá em 60 segundos
Tente novamente quando expirar Sempre solicite um token novo em timeout-or-duplicate
Fila de tokens Nunca coloque tokens na fila – cada um expira independentemente
Operações paralelas Resolva por tarefa, não resolva tudo e depois use
Monitoramento Rastreie a idade do token no momento do envio

Perguntas frequentes

Posso estender a janela do token de 120 segundos?

Não. A expiração é imposta no servidor pelo Google e não pode ser prorrogada de forma alguma. Os 120 segundos são um limite rígido.

O atraso na votação reduz meu tempo de token utilizável?

Sim, um pouco. Se você pesquisar a cada 5 segundos, poderá receber o token até 5 segundos após ele ter sido gerado. Na prática, isso significa que você tem aproximadamente 115 segundos em vez de 120. Isso geralmente não é um problema.

Devo validação antecipada em staging os tokens para tê-los prontos?

Somente se você puder garantir que o token será enviado dentro de 60 a 90 segundos. A validação antecipada em staging é útil para fluxos de trabalho sensíveis à latência (por exemplo, compras competitivas), onde os 15 a 45 segundos extras de tempo de resolução são importantes. Para a maioria dos fluxos de trabalho, a solução sob demanda é mais segura.

Por que o Google usa o mesmo erro para tokens expirados e duplicados?

O Google oculta intencionalmente a distinção para evitar que scripts de automação usem o código de erro para detectar qual caso ocorreu. Ambos os casos têm o mesmo remédio: solicitar um novo token.


Resumo

Os tokens reCAPTCHA expiram após exatamente 120 segundos e só podem ser usados ​​uma vez. O erro de automação mais comum — timeout-or-duplicate — é causado pelo envio de tokens tarde demais ou pela reutilização deles. Ao usarCaptchaAI, resolva os tokens antes do envio, rastreie a idade dos tokens e nunca coloque-os na fila ou reutilize-os. Use o padrão do gerenciador de tempo acima para lidar automaticamente com a expiração e a resolução em fluxos de trabalho de produção.

Artigos relacionados

Os comentários estão desativados para este artigo.