Você resolveu o CAPTCHA da Cloudflare Turnstile e obteve um token válido, mas o site de destino ainda retorna 403 Proibido. Este guia cobre todas as causas.
Por que 403 após token válido
| Causa | Probabilidade |
|---|---|
| Cookie cookie_qa_validacao ausente | Muito comum |
| Token expirou | Comum |
| Endpoint de envio incorreto | Comum |
| Cabeçalhos de solicitação ausentes | Moderado |
| Incompatibilidade de IP entre resolver e enviar | Moderado |
| Cloudflare Turnstile em staging (não catraca) | Às vezes confuso |
Causa 1: Cookie cookie_qa_validacao ausente
Turnstile define cookies durante a validação. Se você não incluir esses cookies em sua solicitação subsequente, a Cloudflare bloqueará você.
import requests
session = requests.Session()
# Step 1: Load the page to get initial cookies
session.get("https://example.com")
# Step 2: Solve Turnstile
token = solve_turnstile(
api_key="YOUR_API_KEY",
sitekey="TURNSTILE_SITEKEY",
pageurl="https://example.com",
)
# Step 3: Submit token to the validation endpoint
# This sets cookie_qa_validacao cookie
resp = session.post("https://example.com/api/verify", data={
"cf-turnstile-response": token,
}, headers={
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "https://example.com",
"Referer": "https://example.com/",
})
# Step 4: Now make your actual request WITH the session cookies
resp = session.get("https://example.com/protected-page")
print(resp.status_code) # Should be 200 now
Causa 2: token expirado
Os tokens da catraca duram aproximadamente 300 segundos, mas use-os imediatamente para obter mais adequado resultados.
import time
# Solve
start = time.time()
token = solve_turnstile(...)
solve_time = time.time() - start
# Check if token is still fresh
if solve_time > 240: # > 4 minutes is risky
print("Token may be too old, solving again...")
token = solve_turnstile(...)
# Submit immediately
submit_token(token)
Causa 3: Método de envio errado
Descubra como o site envia o token Turnstile:
# Some sites use a hidden form field
data = {
"cf-turnstile-response": token,
"username": "user",
"password": "pass",
}
# Some sites use a custom header
headers = {
"X-Turnstile-Token": token,
}
# Some sites use JSON body
json_data = {
"turnstileToken": token,
"email": "user@example.com",
}
Como encontrar o nome do campo correto:
- Abra o navegador DevTools → guia Rede
- Complete o desafio Turnstile manualmente
- Encontre a solicitação de envio do formulário
- Veja o corpo da solicitação para o nome do campo do token
Causa 4: cabeçalhos ausentes
A Cloudflare verifica a consistência dos cabeçalhos das solicitações:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Origin": "https://example.com",
"Referer": "https://staging.example.com/qa-login",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
}
session.headers.update(headers)
Causa 5: Cloudflare Turnstile em staging vs Cloudflare Turnstile
Torniquete e Cloudflare Turnstile em staging são sistemas diferentes:
| Recurso | Torniquete | Cloudflare Turnstile em staging |
|---|---|---|
| Widget | Caixa de seleção visível na página | Tela de desafio de página inteira |
| Método CaptchaAI | turnstile |
turnstile_staging |
| Campo token | cf-turnstile-response |
N/A (baseado em cookies) |
Se você vir um desafio de página inteira, use method=turnstile_staging.
Exemplo de trabalho completo
import requests
import time
import re
def solve_turnstile_and_access(target_url, api_key):
"""Complete flow: solve Turnstile and access protected page."""
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
})
# Load page, get cookies and sitekey
resp = session.get(target_url)
match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if not match:
raise RuntimeError("Turnstile sitekey not found")
sitekey = match.group(1)
# Solve via CaptchaAI
submit_resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": api_key,
"method": "turnstile",
"sitekey": sitekey,
"pageurl": target_url,
"json": 1,
}, timeout=30)
task_id = submit_resp.json()["request"]
# Poll
for _ in range(12):
time.sleep(5)
poll = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get",
"id": task_id, "json": 1,
}, timeout=15)
data = poll.json()
if data.get("status") == 1:
token = data["request"]
break
else:
raise TimeoutError("Solve timeout")
# Submit token using the same session
form_resp = session.post(target_url, data={
"cf-turnstile-response": token,
}, headers={
"Origin": f"https://{requests.utils.urlparse(target_url).netloc}",
"Referer": target_url,
})
return session, form_resp
# Usage
session, resp = solve_turnstile_and_access(
"https://staging.example.com/qa-login",
"YOUR_API_KEY",
)
# session now has valid cookies for subsequent requests
Solução de problemas
| Problema | Causa | Correção |
|---|---|---|
| 403 apesar do token válido | Cookies de sessão ausentes | Use a mesma sessão para todas as solicitações |
| 403 nas páginas subsequentes | cookie_qa_validacao não definido | A validação do token deve retornar cookie |
| Funciona uma vez, depois 403 | Cookie expirou | Resolva para biscoitos frescos |
| Sempre 403 | Desafio de página inteira, não catraca | Use o método turnstile_staging |
Perguntas frequentes
Quanto tempo dura cookie_qa_validacao?
Normalmente de 30 minutos a 24 horas. Se as solicitações subsequentes começarem a falhar, resolva novamente a catraca.
Preciso de um proxy para o Turnstile?
Freqüentemente não - a taxa de sucesso de 100% do CaptchaAI no Turnstile geralmente funciona sem proxies. Adicione um proxy somente se o site verificar a consistência do IP.
Posso passar cookie_qa_validacao para outra sessão?
Sim, mas está vinculado ao User-Agent e pode estar vinculado ao IP. Mantenha ambos consistentes.
Guias Relacionados
Corrigir erros 403 —resolver catraca com CaptchaAI.