Geçerli bir Turnstile token'ı aldınız ama sunucu hâlâ 403 Forbidden dönüyorsa, ilk refleksinizi tersine çevirin: sorun neredeyse hiçbir zaman token'ın kendisinde değildir. 403 çoğu zaman, çözümü tamamladıktan sonra oturum çerezlerini, istek başlıklarını ya da IP tutarlılığını doğru taşımadığınız anlamına gelir. Aşağıda beş temel nedeni görülme sıklığına göre ele alıyor ve her birini birkaç dakikada ayırt etmenizi sağlayan pratik bir yol veriyoruz.
Kod değiştirmeden önce 60 saniyelik triyaj
Satır satır kod kurcalamaya başlamadan önce yanıtı okuyun ve şu üç şeyi hızlıca kontrol edin:
- Yanıt başlıklarında
Server: cloudflareyoksa reddi uygulama katmanı vermiştir; form alan adını kontrol edin. Server: cloudflarevar ve gövde yeniden Turnstile widget'ını gösteriyorsa, çözümden gönderime kadar geçen süreye bakın — 240 saniyeyi aştıysa token büyük olasılıkla eskimiştir.- Süre kısa ama sayfa tam ekran bir bekleme animasyonu gösteriyorsa, karşınızdaki Turnstile değil Cloudflare doğrulama akışıdır.
Bu üç kontrol vakaların çoğunu tek başına eler; geri kalanı için aşağıdaki nedenler tablosuna ve ilgili bölümlere geçin.
Geçerli token'a rağmen neden 403 alırsınız
| Neden | Görülme sıklığı |
|---|---|
| qa_session_cookie çerezi eksik | Çok yaygın |
| Token'ın süresi doldu | Yaygın |
| Yanlış gönderim uç noktası | Yaygın |
| İstek başlıkları eksik | Orta |
| Çözme ve gönderim arasında IP uyuşmazlığı | Orta |
| Cloudflare doğrulama akışı (Turnstile değil) | Sık karıştırılır |
Neden 1: Eksik qa_session_cookie çerezi
Turnstile, doğrulama sırasında çerezleri ayarlar. Bu çerezleri sonraki isteğinize eklemezseniz Cloudflare sizi engeller. Bu yüzden çözümün ardından gelen her istek aynı requests.Session üzerinden gitmelidir.
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 qa_session_cookie 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
Bu bölümde iki nokta çoğu 403'ü açıklar:
- Çözüm, gönderim ve sonraki tüm istekler tek bir
Sessionüzerinden gitmelidir. - Çerez yalnızca doğrulama uç noktasından döner; sayfayı yükleyen ilk
GETbunu ayarlamaz.
Neden 2: Token'ın süresi doldu
Turnstile token'larının ömrü yaklaşık 300 saniyedir; yine de en iyi sonuç için token'ı hemen kullanın. Çözüm ile gönderim arasında dört dakikadan uzun beklerseniz token'ı yeniden çözmek daha güvenlidir.
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)
Neden 3: Yanlış gönderim yöntemi
Token'ı göndermeden önce sitenin bu token'ı tam olarak nasıl beklediğini belirleyin:
# 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",
}
Doğru alan adını DevTools ile birkaç adımda bulursunuz:
- Tarayıcı DevTools → Ağ (Network) sekmesini açın
- Turnstile doğrulamasını elle tamamlayın
- Form gönderim isteğini bulun
- Token alan adı için istek gövdesini inceleyin
Neden 4: Eksik başlıklar
Cloudflare, istek başlıklarını tutarlılık açısından denetler. User-Agent, Origin ve Referer değerleri tarayıcının gönderdikleriyle eşleşmezse geçerli bir token bile 403 ile dönebilir.
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)
Neden 5: Cloudflare doğrulama akışı mı, Turnstile mı?
Turnstile ile Cloudflare doğrulama akışı birbirinden farklı sistemlerdir ve farklı bir yöntem gerektirir:
| Özellik | Turnstile | Cloudflare doğrulama akışı |
|---|---|---|
| Widget | Sayfada görünür onay kutusu | Tam sayfa doğrulama ekranı |
| CaptchaAI yöntemi | turnstile |
cloudflare_challenge |
| Token alanı | cf-turnstile-response |
Yok (çerez tabanlı) |
Tam sayfa bir doğrulama ekranı görüyorsanız turnstile yerine method=cloudflare_challenge kullanın.
Uçtan uca çalışan örnek
Aşağıdaki fonksiyon, sitekey çıkarımından token gönderimine kadar tüm akışı tek bir oturumda toplar; çerezler böylece korunur ve sonraki isteklere taşınır:
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
Hızlı sorun giderme tablosu
En sık görülen dört durum ve doğrudan uygulanacak düzeltmeleri:
| Sorun | Neden | Düzeltme |
|---|---|---|
| Geçerli token'a rağmen 403 | Eksik oturum çerezleri | Tüm istekler için aynı oturumu kullanın |
| Sonraki sayfalarda 403 | qa_session_cookie ayarlanmadı | Token doğrulaması çerez döndürmeli |
| Bir kez çalışıp sonra 403 | Çerezin süresi doldu | Taze çerez için yeniden çözün |
| Her zaman 403 | Turnstile değil, tam sayfa doğrulama | cloudflare_challenge yöntemini kullanın |
Gerçek bir senaryo: yalnızca ikinci istekte 403
Türkiye'deki bir e-ticaret ekibinin, ödeme adımını staging.example.com üzerinde test eden QA hattını düşünün. Boru hattı Turnstile token'ını gönderiyor, form gönderimi 200 OK dönüyor ve korumalı sayfa geliyor. İki dakika sonra aynı akış /api/orders uç noktasını çağırınca 403 alıyor. Ekip önce token süresini suçladı; oysa token ilk gönderimden sonra zaten atılmıştı.
Kök neden: HTTP istemcisi her istek için bir yardımcı fonksiyonun içinde yeniden oluşturuluyordu. Her yeni istek boş bir çerez kabıyla açıldığı için ilk yanıtta ayarlanan qa_session_cookie ikinci isteğe hiç ulaşmadı.
Düzeltme: requests.Session() nesnesini yardımcı fonksiyonun dışına taşıyın ve parametre olarak geçirin. Korumalı origin'e yapılan her çağrı aynı oturumu kullanmalıdır. Token'ı tekrar göndermeniz gerekmez — sizi ileri taşıyan şey çerezdir. KVKK kapsamındaki kişisel verilerle çalışıyorsanız bu testleri yalnızca yetkili QA ortamlarında yürütün.
Destek talebi açmadan önce kontrol listesi
Bildirilen 403'lerin çoğu aşağıdaki listede yakalanır; solver'ı suçlamadan önce hepsini geçin:
- Çözüm ve gönderim sırasında aynı
User-Agentdeğeri kullanıldı - Çözüm ve gönderim aynı çıkış IP'sinden yapıldı (ya da proxy oturum düzeyinde sabitlendi)
OriginveRefererbaşlıkları hedef sayfa URL'siyle eşleşiyor- Token, alındıktan sonraki 240 saniye içinde gönderildi
- Token yalnızca bir kez gönderildi (Turnstile token'ları tek kullanımlıktır)
- Form alan adı DevTools'ta doğrulandı (
cf-turnstile-responsemü, özel bir ad mı?) requests.Session()çözüm → gönderim → sonraki isteklerde yeniden kullanıldıdata-sitekeyher çalıştırmada yeniden çıkarıldı (sitekey'ler değişebilir)- Sayfanın gerçekten Turnstile sunduğu, tam sayfa doğrulama olmadığı doğrulandı
- Sunucu, gönderimden sonra
Set-Cookieile çerez döndürdü
Sık sorulan sorular
Token geçerli olduğu hâlde neden 403 alıyorum?
Çünkü 403'ü çoğunlukla token değil, çözümden sonra taşınamayan oturum çerezleri tetikler. Çözüm ile sonraki isteklerin aynı oturumu, aynı User-Agent'ı ve aynı IP'yi kullandığından emin olun.
Turnstile token'ı ne kadar süre geçerli kalır?
Yaklaşık 300 saniye. Güvenli tarafta kalmak için token'ı aldıktan sonraki 240 saniye içinde gönderin; daha uzun beklediyseniz yeniden çözün.
Aynı oturumu her istekte kullanmak neden bu kadar önemli?
Çünkü sizi korumalı sayfada tutan şey token değil, doğrulamadan sonra ayarlanan çerezdir. Her seferinde yeni bir istemci açarsanız çerez kabı boş kalır ve 403 alırsınız.
Proxy kullanmadan Turnstile çözebilir miyim?
Çoğu durumda evet. Yalnızca site IP tutarlılığını denetliyorsa proxy'yi oturum düzeyinde sabitleyin; çözüm ve gönderim aynı IP'den gitmelidir.
İlgili kılavuzlar
403 döngüsünü kırın — Turnstile'ı CaptchaAI ile çözün.