Use Cases

CAPTCHA Korumalı Web Sitelerini Kazıma

CAPTCHA korumalı bir siteyi güvenilir şekilde kazımanın yolu, siteyi baştan zorlamak değildir: kazıyıcınızı normal çalıştırın, karşınıza bir doğrulama çıktığı anda türünü tanıyın, CaptchaAI API'ye gönderip dönen token'ı forma enjekte edin ve kaldığınız yerden devam edin. Bu yazı, reCAPTCHA'dan Cloudflare Turnstile'a en sık karşılaşılan korumaları bu akışla çözen, üretimde ayakta kalan bir kazıyıcının nasıl kurulacağını gösterir.

Pratikte akış her zaman aynı dört adımdan oluşur:

  1. Kazıyıcı sayfayı çeker ve yanıtta bir CAPTCHA işareti olup olmadığını kontrol eder.
  2. Varsa doğrulama türünü tanır ve gerekli parametreleri (sitekey, pageurl) çıkarır.
  3. Bu parametreleri CaptchaAI API'ye gönderir ve sonucu sorgulayarak token'ı alır.
  4. Token'ı forma enjekte eder, isteği tekrarlar ve kaldığı yerden devam eder.

E-ticaret fiyat takibi, pazar araştırması veya QA otomasyonu üzerinde çalışan bir geliştirici için bu, tek seferlik bir numara değil tekrarlanabilir bir iş akışı meselesidir. Aşağıdaki desenler, CAPTCHA'yı sayfa başına tek tek uğraştığınız bir engel olmaktan çıkarıp kazıma hattınızın sıradan bir adımına dönüştürür.

Karşılaşacağınız CAPTCHA türleri ve CaptchaAI yöntemleri

Bir siteyi kazımadan önce hangi doğrulama türüyle karşı karşıya olduğunuzu bilmek, doğru method değerini seçmenizi sağlar. En yaygın türler ve CaptchaAI API'de karşılık gelen yöntemler:

CAPTCHA Nerede karşınıza çıkar CaptchaAI yöntemi
reCAPTCHA v2 Giriş ve arama formları method=userrecaptcha
reCAPTCHA v3 Sayfa arka planında puanlama method=userrecaptcha&version=v3
Cloudflare Turnstile Cloudflare arkasındaki siteler method=turnstile
Cloudflare doğrulama akışı Tam sayfa Cloudflare bloğu method=cloudflare_challenge
Image/OCR CAPTCHA Eski siteler, görsel kodlar method=base64
GeeTest v3 Kaydırmalı/yapboz doğrulamalar method=geetest
BLS CAPTCHA BLS vize başvuru portalları method=bls

Strateji 1: CAPTCHA'yı yalnızca göründüğünde çözün

En güvenilir yaklaşım, siteyi normal şekilde kazımak ve doğrulamayı yalnızca gerçekten ortaya çıktığında çözmektir. Kazıyıcı her yanıtı kontrol eder; sayfada bir CAPTCHA işareti görürse çözüm akışını devreye alır, görmezse hiç API çağrısı yapmadan devam eder. Böylece hem gereksiz çözüm maliyetinden hem de fazladan gecikmeden kaçınırsınız.

Aşağıdaki ProtectedScraper sınıfı tam olarak bu mantığı uygular: yanıt HTML'inde g-recaptcha veya cf-turnstile işaretlerini arar, ilgili sitekey'i çıkarır, CaptchaAI'ye gönderir ve dönen token'ı forma ekleyerek isteği tekrarlar.

import requests
import time
from bs4 import BeautifulSoup

API_KEY = "YOUR_API_KEY"

class ProtectedScraper:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })

    def scrape(self, url):
        resp = self.session.get(url)

        # Check for CAPTCHA
        if self._has_captcha(resp.text):
            resp = self._handle_captcha(resp.text, url)

        return resp.text

    def _has_captcha(self, html):
        indicators = ["g-recaptcha", "cf-turnstile", "h-captcha", "captcha"]
        return any(ind in html.lower() for ind in indicators)

    def _handle_captcha(self, html, url):
        soup = BeautifulSoup(html, "html.parser")

        # reCAPTCHA v2
        rc = soup.find("div", class_="g-recaptcha")
        if rc:
            token = self._solve_recaptcha(rc["data-sitekey"], url)
            return self.session.post(url, data={"g-recaptcha-response": token})

        # Cloudflare Turnstile
        ts = soup.find("div", class_="cf-turnstile")
        if ts:
            token = self._solve_turnstile(ts["data-sitekey"], url)
            return self.session.post(url, data={"cf-turnstile-response": token})

        raise Exception("Unknown CAPTCHA type")

    def _solve_recaptcha(self, site_key, page_url):
        resp = requests.get("https://ocr.captchaai.com/in.php", params={
            "key": API_KEY, "method": "userrecaptcha",
            "googlekey": site_key, "pageurl": page_url
        })
        return self._poll(resp.text.split("|")[1])

    def _solve_turnstile(self, site_key, page_url):
        resp = requests.get("https://ocr.captchaai.com/in.php", params={
            "key": API_KEY, "method": "turnstile",
            "sitekey": site_key, "pageurl": page_url
        })
        return self._poll(resp.text.split("|")[1])

    def _poll(self, task_id):
        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": API_KEY, "action": "get", "id": task_id
            })
            if result.text == "CAPCHA_NOT_READY": continue
            if result.text.startswith("OK|"): return result.text.split("|")[1]
            raise Exception(result.text)
        raise TimeoutError()

# Usage
scraper = ProtectedScraper()
html = scraper.scrape("https://example.com/data")

Çözüm süresi türe göre değişir: Cloudflare Turnstile genellikle 10 saniyenin altında, reCAPTCHA v2 ise 60 saniyenin altında yüksek başarı oranıyla çözülür. _poll döngüsü 5 saniyelik aralıklarla sonucu sorgular ve OK| yanıtı geldiğinde token'ı döndürür; bu yüzden ana kazıma döngünüzü bu bekleme süresine göre tasarlayın.

Strateji 2: CAPTCHA'sı bilinen sayfaları önceden çözün

Bazı sayfaların (örneğin belirli bir arama ya da giriş uç noktasının) her zaman CAPTCHA döndürdüğünü biliyorsanız, sayfayı hiç çekmeden token'ı çözüp isteği doğrudan token'la gönderebilirsiniz. Bu, fazladan bir GET isteğini atlar ve akışı kısaltır.

def scrape_known_captcha_page(url, site_key):
    # Solve before even loading the page
    token = solve_recaptcha(site_key, url)

    # Submit directly with token
    resp = requests.post(url, data={
        "g-recaptcha-response": token,
        "query": "search term"
    })
    return resp.text

Bu desen, sitekey'in sabit ve önceden bilindiği durumlarda idealdir. Sitekey sayfadan sayfaya değişiyorsa Strateji 1'deki dinamik çıkarma yöntemine geri dönün — aksi halde geçersiz bir sitekey ile boş token alırsınız.

Strateji 3: Cloudflare korumalı siteler

Cloudflare'in tam sayfa doğrulama akışı arkasındaki siteler, isteklerin geçerli sayılması için bir oturum çerezine (qa_session_cookie) ihtiyaç duyar. method=cloudflare_challenge ile bu akışı çözer, dönen çerezi ve User-Agent'ı sonraki tüm isteklerde aynen kullanırsınız.

def get_cloudflare_clearance(url, proxy):
    resp = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": API_KEY,
        "method": "cloudflare_challenge",
        "pageurl": url,
        "proxy": proxy,
        "proxytype": "HTTP"
    })
    task_id = resp.text.split("|")[1]

    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id
        })
        if result.text == "CAPCHA_NOT_READY": continue
        if "qa_session_cookie" in result.text:
            # Parse qa_session_cookie and user_agent from response
            return result.text
    raise TimeoutError()

Kritik nokta: çözümden dönen çerez, onu üreten IP ve User-Agent ile eşleşmek zorundadır. Aynı proxy'yi ve aynı User-Agent'ı tüm oturum boyunca sabit tutmazsanız, site sizi yeniden doğrulama akışına sokar ve çerez bir işe yaramaz.

Birden çok sayfayı sırayla kazıma

Tek sayfalar yerine sayfalı (paginated) bir listeyi kazırken, her sayfa için aynı çözüm mantığını yeniden kullanır ve istekler arasına rastgele gecikmeler koyarsınız. Aşağıdaki desen, her sayfayı ProtectedScraper üzerinden geçirir, öğeleri toplar ve bir sayfa başarısız olsa bile tüm işi durdurmadan devam eder.

def scrape_multiple_pages(base_url, site_key, pages):
    scraper = ProtectedScraper()
    results = []

    for page in pages:
        url = f"{base_url}?page={page}"
        try:
            html = scraper.scrape(url)
            soup = BeautifulSoup(html, "html.parser")
            items = soup.find_all("div", class_="item")
            results.extend([item.text.strip() for item in items])
            print(f"Page {page}: {len(items)} items")
        except Exception as e:
            print(f"Page {page} failed: {e}")

        time.sleep(random.uniform(2, 5))

    return results

time.sleep(random.uniform(2, 5)) satırı, isteklerinizi daha insan temposuna yaklaştırarak sitenin sizi hız sınırına takmasını azaltır. Yüksek hacimli işlerde bu aralığı yukarı çekmek, CAPTCHA'nın her sayfada tetiklenme olasılığını da düşürür.

Thread planlaması ve maliyet

CaptchaAI, çözüm başına değil eşzamanlı thread başına ücretlendirir ve her planda thread başına sınırsız çözüm vardır. Kazıma hattınızın hızını belirleyen şey, kaç isteği aynı anda çözüme gönderdiğinizdir:

  • Tek bir kazıyıcı ve düşük hacim için BASIC ($15/ay, 5 thread) çoğu zaman yeterlidir.
  • Paralel çok sayfalı işler veya birden çok kazıyıcı çalıştırıyorsanız STANDARD ($30/ay, 15 thread) ya da ADVANCE ($90/ay, 50 thread) daha akıcı bir throughput sağlar.

Türkiye'deki geliştiriciler için öngörülebilir aylık USD fiyatlandırma, kur dalgalanmasından bağımsız bir maliyet planlaması demektir; çözüm başına sürpriz faturalar oluşmaz. Thread sayınızı, hedef CAPTCHA türünün çözüm süresine ve saatlik istek hacminize göre seçin.

KVKK ve yetkili kazıma

Türkiye'de kişisel veri içeren sayfaları kazırken KVKK (Kişisel Verilerin Korunması Kanunu) çerçevesi devreye girer: topladığınız veri kişisel veri niteliği taşıyorsa, işleme amacınızın ve hukuki dayanağınızın net olması gerekir. CaptchaAI'yi yalnızca yetkiniz olan işlerde — kendi sistemlerinizin QA testleri veya izinli veri toplama iş akışları kapsamında — kullanın.

Bir doğrulamayı teknik olarak çözebiliyor olmanız, o veriyi toplama hakkınız olduğu anlamına gelmez. Hedef sitenin kullanım şartlarını ve robots politikalarını her zaman önce gözden geçirin.

Sorun giderme

Sorun Çözüm
Her sayfada CAPTCHA çıkıyor İstek oranını düşürün ve proxy kullanın
Token çözümden sonra reddedildi Token'ın süresi dolmuş olabilir; 120 saniye içinde kullanın
Cloudflare çerezine rağmen engelleniyor Tüm isteklerde aynı proxy ve User-Agent'ı kullanın
Çözümden sonra farklı bir sayfa dönüyor Ek yönlendirmeleri ve çerezleri kontrol edin

Sık sorulan sorular

Kazıma sırasında CAPTCHA'yı çözmek ne kadar sürer ve nasıl ücretlendirilir?

Süre türe göre değişir: Cloudflare Turnstile genellikle 10 saniyenin altında, reCAPTCHA v2 ise 60 saniyenin altında çözülür. Ücretlendirme çözüm başına değil, eşzamanlı thread başınadır ve her planda thread başına sınırsız çözüm bulunur.

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

Hayır. CaptchaAI şu anda hCaptcha ve FunCaptcha (Arkose Labs) çözmez. Desteklenen türler reCAPTCHA v2/v3, Cloudflare Turnstile ve doğrulama akışı, GeeTest v3, görsel/OCR, grid ve BLS'tir; CaptchaFox, Friendly Captcha ve Lemin ise beta aşamasındadır.

JavaScript ile oluşturulan sayfaları nasıl kazırım?

Sayfayı Selenium, Puppeteer veya Playwright ile render edin, ardından CAPTCHA parametrelerini (sitekey, pageurl) çıkarıp CaptchaAI ile çözün. Ayrıntılı akış için Selenium ile CAPTCHA çözümü rehberine bakın.

Kazıyıcım her sayfada CAPTCHA ile karşılaşıyorsa ne yapmalıyım?

Bu genellikle fazla agresif bir istek temposunun işaretidir. İstek aralığını artırın, oturumu tutarlı tutun ve isteklerinizi proxy'ler arasında dağıtın; çoğu durumda CAPTCHA sıklığı belirgin biçimde düşer.

İlgili rehberler

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