Troubleshooting

Aynı Sitede reCAPTCHA v2 ve Cloudflare Turnstile'yi Çözme

Çözüm tek cümlede özetlenir: sağlayıcıyı sabit kodlamayın. Her sayfa yüklemesinde hangi CAPTCHA'nın geldiğini algılayın ve doğru çözüm yöntemine yönlendirin. Aynı alan adı altında bir sayfada reCAPTCHA v2, diğerinde Cloudflare Turnstile çıkması Türkiye'deki e-ticaret ve fintech projelerinde giderek yaygınlaşıyor; tek bir yönteme kilitlenen otomasyon, diğer türle karşılaştığı anda kırılır. Bu rehber iki sağlayıcıyı tek iş akışında algılayıp CaptchaAI ile çözmenin pratik yolunu gösterir.

Aynı sitede neden iki farklı CAPTCHA sağlayıcısı çıkar?

Çoğu zaman bu bir hata değil, bilinçli bir tasarım tercihidir. En sık karşılaşılan senaryolar şunlardır:

Senaryo Nasıl görünür?
Farklı sayfalar, farklı sağlayıcılar Giriş = reCAPTCHA, ödeme = Turnstile
A/B testi Aynı sayfa ziyaretçiye rastgele birini gösterir
Süren bir taşıma Eski sayfalarda reCAPTCHA, yeni sayfalarda Turnstile
Hata durumunda yedek Birincil sağlayıcı yüklenemezse ikincisine düşer
Bölgesel farklılık ABD ziyaretçilerine reCAPTCHA, AB'ye Turnstile (GDPR)

Doğru yaklaşım: sağlayıcıyı her istekte algılayın

Kural basit: HTML'i çekin, sağlayıcıya özgü işareti (cf-turnstile veya g-recaptcha) arayın, data-sitekey'i çıkarın ve türe uygun method ile CaptchaAI'ye gönderin. reCAPTCHA için method=userrecaptcha ve googlekey, Turnstile için method=turnstile ve sitekey kullanılır. Uç noktalar her iki tür için de aynıdır: in.php ile görevi gönderir, res.php ile sonucu sorgularsınız. Böylece sağlayıcı sayfadan sayfaya veya ziyaretten ziyarete değişse bile aynı kod çalışmaya devam eder.

Python: otomatik algılama ve çözüm

Aşağıdaki detect_captcha_type fonksiyonu önce Turnstile'i, sonra reCAPTCHA'yı (script ile oluşturulan varyant dahil) arar ve bulduğu türe göre doğru yanıt alanını döndürür. solve_captcha ise algılanan türü CaptchaAI üzerinden çözer:

import requests
import time
import re
from dataclasses import dataclass

API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


@dataclass
class CaptchaInfo:
    provider: str     # "recaptcha" or "turnstile"
    method: str       # API method name
    sitekey: str
    pageurl: str
    response_field: str  # Form field name for the token


def detect_captcha_type(html, pageurl):
    """
    Detect which CAPTCHA provider is on the page.
    Returns CaptchaInfo or None.
    """
    # Check for Turnstile
    turnstile_match = re.search(
        r'class=["\'][^"\']*cf-turnstile[^"\']*["\'][^>]*data-sitekey=["\']([^"\']+)["\']',
        html,
    )
    if not turnstile_match:
        turnstile_match = re.search(
            r'data-sitekey=["\']([^"\']+)["\'][^>]*class=["\'][^"\']*cf-turnstile',
            html,
        )

    if turnstile_match:
        return CaptchaInfo(
            provider="turnstile",
            method="turnstile",
            sitekey=turnstile_match.group(1),
            pageurl=pageurl,
            response_field="cf-turnstile-response",
        )

    # Check for reCAPTCHA
    recaptcha_match = re.search(
        r'class=["\'][^"\']*g-recaptcha[^"\']*["\'][^>]*data-sitekey=["\']([^"\']+)["\']',
        html,
    )
    if not recaptcha_match:
        recaptcha_match = re.search(
            r'data-sitekey=["\']([^"\']+)["\'][^>]*class=["\'][^"\']*g-recaptcha',
            html,
        )

    # Also check for script-rendered reCAPTCHA
    if not recaptcha_match:
        recaptcha_match = re.search(
            r'grecaptcha\.render\([^,]+,\s*\{[^}]*["\']sitekey["\']\s*:\s*["\']([^"\']+)["\']',
            html,
        )

    if recaptcha_match:
        return CaptchaInfo(
            provider="recaptcha",
            method="userrecaptcha",
            sitekey=recaptcha_match.group(1),
            pageurl=pageurl,
            response_field="g-recaptcha-response",
        )

    return None


def solve_captcha(info):
    """Solve any detected CAPTCHA type via CaptchaAI."""
    params = {
        "key": API_KEY,
        "method": info.method,
        "json": 1,
    }

    if info.method == "userrecaptcha":
        params["googlekey"] = info.sitekey
        params["pageurl"] = info.pageurl
    elif info.method == "turnstile":
        params["sitekey"] = info.sitekey
        params["pageurl"] = info.pageurl

    resp = requests.post(SUBMIT_URL, data=params, timeout=30).json()
    if resp.get("status") != 1:
        raise RuntimeError(f"Submit failed: {resp.get('request')}")

    task_id = resp["request"]
    for _ in range(60):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve failed: {poll.get('request')}")

    raise RuntimeError("Timeout")


def process_page(session, url):
    """Fetch page, detect CAPTCHA type, solve, and return form-ready data."""
    response = session.get(url)
    captcha_info = detect_captcha_type(response.text, url)

    if not captcha_info:
        print(f"No CAPTCHA detected on {url}")
        return None

    print(f"Detected {captcha_info.provider} on {url}")
    print(f"  Sitekey: {captcha_info.sitekey[:30]}...")

    token = solve_captcha(captcha_info)
    print(f"  Solved: {token[:30]}...")

    return {
        "provider": captcha_info.provider,
        "response_field": captcha_info.response_field,
        "token": token,
    }


# Usage: Handle multiple pages with different providers
session = requests.Session()

pages = [
    "https://staging.example.com/qa-login",      # Might have reCAPTCHA
    "https://example.com/checkout",   # Might have Turnstile
]

for url in pages:
    result = process_page(session, url)
    if result:
        form_data = {result["response_field"]: result["token"]}
        # Add other form fields...
        # session.post(url, data=form_data)

Node.js: dinamik CAPTCHA algılama

Aynı mantığın tarayıcısız (headless) bir Node.js akışındaki karşılığı aşağıdadır. detectCaptchaType sayfayı tarar, solveCaptcha görevi gönderip sonucu sorgular:

const API_KEY = "YOUR_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

function detectCaptchaType(html, pageurl) {
  // Turnstile
  const turnstileMatch = html.match(/cf-turnstile[^>]*data-sitekey=["']([^"']+)["']/);
  if (turnstileMatch) {
    return { provider: "turnstile", method: "turnstile", sitekey: turnstileMatch[1], pageurl, field: "cf-turnstile-response" };
  }

  // reCAPTCHA
  const recaptchaMatch = html.match(/g-recaptcha[^>]*data-sitekey=["']([^"']+)["']/);
  if (recaptchaMatch) {
    return { provider: "recaptcha", method: "userrecaptcha", sitekey: recaptchaMatch[1], pageurl, field: "g-recaptcha-response" };
  }

  // Script-rendered reCAPTCHA
  const scriptMatch = html.match(/sitekey["']\s*:\s*["']([^"']+)["']/);
  if (scriptMatch) {
    return { provider: "recaptcha", method: "userrecaptcha", sitekey: scriptMatch[1], pageurl, field: "g-recaptcha-response" };
  }

  return null;
}

async function solveCaptcha(info) {
  const body = new URLSearchParams({ key: API_KEY, method: info.method, json: "1" });
  if (info.method === "userrecaptcha") { body.set("googlekey", info.sitekey); body.set("pageurl", info.pageurl); }
  else if (info.method === "turnstile") { body.set("sitekey", info.sitekey); body.set("pageurl", info.pageurl); }

  const resp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
  if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);

  const taskId = resp.request;
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return poll.request;
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

async function processPage(url) {
  const response = await fetch(url);
  const html = await response.text();
  const info = detectCaptchaType(html, url);

  if (!info) { console.log(`No CAPTCHA on ${url}`); return null; }
  console.log(`${info.provider} detected on ${url}`);

  const token = await solveCaptcha(info);
  return { provider: info.provider, field: info.field, token };
}

// Usage
const pages = ["https://staging.example.com/qa-login", "https://example.com/checkout"];
for (const url of pages) {
  const result = await processPage(url);
  if (result) {
    console.log(`Solved ${result.provider}: ${result.token.substring(0, 30)}...`);
  }
}

Sağlayıcı algılama referansı

Kod yazmadan önce hangi işaretin hangi sağlayıcıya karşılık geldiğini bilmek işinizi hızlandırır:

Sağlayıcı HTML işareti Script URL'si Yanıt alanı
reCAPTCHA v2 class="g-recaptcha" google.com/recaptcha/api.js g-recaptcha-response
Cloudflare Turnstile class="cf-turnstile" challenges.cloudflare.com/turnstile cf-turnstile-response
hCaptcha class="h-captcha" js.hcaptcha.com/1/api.js h-captcha-response

CaptchaAI bu tablodaki reCAPTCHA v2 ve Cloudflare Turnstile türlerini çözer; hCaptcha desteklenmez ve yalnızca algılama/teşhis amacıyla listelenmiştir.

Sık karşılaşılan sorunlar ve çözümleri

Sorun Neden Çözüm
Yanlış CAPTCHA türü algılandı Regex yanlış öğeyle eşleşti Yalnızca data-sitekey'e değil, önce sağlayıcıya özgü sınıf adlarına bakın
Token doğru çözüldükten sonra reddedildi Yanlış yanıt alanı adı kullanıldı Alan adını sağlayıcıyla eşleştirin: g-recaptcha-response ile cf-turnstile-response
CAPTCHA türü ziyaretler arasında değişiyor A/B testi veya coğrafi seçim Türü hep dinamik algılayın; sağlayıcıyı asla sabit kodlamayın
Tek sayfada iki sağlayıcı da algılandı Biri gizli/pasif olabilir Öğe görünürlüğünü denetleyin — yalnızca görünür CAPTCHA'yı çözün
Script ile oluşturulan CAPTCHA algılanamıyor Kaynakta HTML işareti yok Script içinde grecaptcha.render() veya turnstile.render() çağrılarını arayın

Türkiye'den bir senaryo: e-ticaret ödeme akışını test etmek

Diyelim ki bir e-ticaret müşterisi için ödeme akışını uçtan uca test eden bir otomasyon yazıyorsunuz. Giriş sayfası hâlâ reCAPTCHA v2 kullanırken, yeni taşınan ödeme adımı Cloudflare Turnstile'ye geçmiş olabilir — bu, Turnstile'ye göç eden Türk sitelerinde tipik bir ara durumdur. Sağlayıcıyı ilk sayfadan önbelleğe alırsanız, staging.example.com/qa-login üzerinde çalışan kod ödeme adımında sessizce kırılır. Doğru yaklaşım, her istekte türü yeniden algılamaktır.

Maliyet tarafında iki sağlayıcı kullanmak ek yük getirmez: CaptchaAI thread bazlı ücretlendirir, çözüm başına veya CAPTCHA türü başına ücret almaz. reCAPTCHA v2 ve Turnstile aynı plandaki thread havuzunu paylaşır; BASIC ($15/ay, 5 thread) ile başlayıp iş yükünüz büyüdükçe üst planlara geçebilirsiniz. Fiyatların USD üzerinden ve thread sayısına göre sabit olması, TL'deki dalgalanmadan bağımsız öngörülebilir bir bütçe demektir — Türk geliştiriciler için gerçek bir avantaj.

Bir uyarı: kişisel veri toplayan kazıma iş akışları KVKK kapsamına girer. CaptchaAI'yi yalnızca yetkiniz olan sayfalar ve QA/veri toplama süreçleri için kullanın; test hedeflerinizi staging.example.com gibi kendi ortamlarınızla sınırlayın.

SSS

İki sağlayıcıyı çözmek maliyeti artırır mı?

Hayır. CaptchaAI thread bazlı ücretlendirir; çözüm başına veya CAPTCHA türü başına ek ücret yoktur. reCAPTCHA v2 ve Turnstile aynı plandaki thread havuzunu paylaşır — BASIC ($15/ay, 5 thread) ile ikisini de çözebilirsiniz.

Otomatik algılama iş akışını yavaşlatır mı?

Algılama tarafındaki maliyet, sayfa HTML'i üzerinde birkaç regex eşleşmesinden ibarettir ve pratikte ölçülemez. Asıl süre CAPTCHA'nın çözülmesinde geçer; bu da türe bağlıdır, sağlayıcıyı önceden bilmek çözüm süresini kısaltmaz.

Sayfada hem reCAPTCHA hem Turnstile görünüyorsa hangisini çözmeliyim?

Genellikle yalnızca biri etkindir. Görünür olan ve boş olmayan bir data-sitekey taşıyan widget'i çözün; gizli ya da display:none olan öğeyi yok sayın.

CaptchaAI hCaptcha'yı da çözüyor mu?

Hayır. CaptchaAI reCAPTCHA v2/v3, Cloudflare Turnstile ve Challenge ile GeeTest v3 gibi türleri çözer; hCaptcha ve FunCaptcha desteklenmez. Algılama tablosundaki hCaptcha satırı yalnızca teşhis içindir.

Sağlayıcı oturum ortasında değişirse ne olur?

Bir site oturum sırasında reCAPTCHA'dan Turnstile'ye geçebilir (örneğin reCAPTCHA yüklenemezse). Bu yüzden sağlayıcıyı ilk ziyaretten önbelleğe almayın; her sayfa isteğinde türü yeniden algılayın.

İlgili makaleler

Sonraki adımlar

Birden fazla CAPTCHA sağlayıcısı kullanan siteleri tek iş akışında yönetin — CaptchaAI API anahtarınızı alın ve otomatik algılamayı devreye alın.

İlgili kılavuzlar:

Bu makale için yorumlar devre dışı bırakılmıştır.