Integrations

Scrapy + CaptchaAI Entegrasyon Kılavuzu

Bir Scrapy taraması, hedef sayfa reCAPTCHA v2 veya görüntü tabanlı bir CAPTCHA döndürdüğü anda durur — ve ürün verisi yerine bir doğrulama sayfası toplarsınız. Bunu çözmenin temiz yolu, çözümü doğrudan tarama akışının içine gömen bir downloader middleware'dir: sayfadaki sitekey'i yakalar, CaptchaAI API'ye gönderir, dönen token'ı forma ekleyip isteği yeniden yürütür. Bu kılavuz o middleware'i sıfırdan kurar; mevcut spider kodunuza dokunmanıza gerek kalmaz.

Nasıl çalışır: tarama akışının içinde çözüm

Akış dört adımdan oluşur ve tamamı middleware katmanında yaşar:

  1. Tespit — middleware, gelen HTML yanıtında data-sitekey özniteliğini arar.
  2. Gönderim — bir sitekey bulursa, sayfa URL'siyle birlikte CaptchaAI'nin in.php uç noktasına bir görev gönderir ve bir görev kimliği alır.
  3. Sorgulamares.php uç noktasını birkaç saniyede bir sorgular (periyodik sorgulama) ve çözümün hazır olmasını bekler.
  4. Enjeksiyon — dönen token'ı request.meta üzerine yazar; spider bu token'ı g-recaptcha-response alanıyla forma ekleyip sayfayı yeniden gönderir.

Örümcek mantığınızın bu ayrıntıların hiçbirini bilmesi gerekmez — middleware tüm işi arka planda yapar, siz yalnızca ayrıştırma kurallarınıza odaklanırsınız.

Başlamadan önce: gereksinimler

Kuruluma başlamadan önce ortamınızda şunların bulunması gerekir. Sürüm numaralarını tablodaki gibi (nokta ile) bırakın; bunlar kod düzeyi değerlerdir.

Gereksinim Ayrıntılar
Python 3.8+
Scrapy 2.5+
requests CaptchaAI API çağrıları için
CaptchaAI API anahtarı ücretsiz hesabınızdan alın
pip install scrapy requests

CaptchaAI çözücü sınıfı

İlk olarak, CaptchaAI API'sini saran küçük bir çözücü sınıfı yazın. Scrapy proje kökünüzde captcha_solver.py dosyasını oluşturun. Sınıf iki metot sunar:

  • solve_recaptcha — görevi userrecaptcha yöntemiyle gönderir ve token hazır olana kadar res.php'yi sorgular.
  • solve_image — base64 kodlu görüntü CAPTCHA'ları için aynı gönder-sorgula desenini izler.

Varsayılan zaman aşımı reCAPTCHA için 300 saniye, görüntü için 120 saniyedir — yavaş ağlarda bu değerleri artırabilirsiniz.

import requests
import time


class CaptchaAISolver:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://ocr.captchaai.com"

    def solve_recaptcha(self, site_key, page_url, timeout=300):
        resp = requests.get(f"{self.base_url}/in.php", params={
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": site_key,
            "pageurl": page_url,
        })

        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {resp.text}")

        task_id = resp.text.split("|")[1]
        deadline = time.time() + timeout

        while time.time() < deadline:
            time.sleep(5)
            result = requests.get(f"{self.base_url}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
            })

            if result.text == "CAPCHA_NOT_READY":
                continue
            if result.text.startswith("OK|"):
                return result.text.split("|", 1)[1]
            raise Exception(f"Solve failed: {result.text}")

        raise TimeoutError(f"Task {task_id} timed out")

    def solve_image(self, image_base64, timeout=120):
        resp = requests.get(f"{self.base_url}/in.php", params={
            "key": self.api_key,
            "method": "base64",
            "body": image_base64,
        })

        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {resp.text}")

        task_id = resp.text.split("|")[1]
        deadline = time.time() + timeout

        while time.time() < deadline:
            time.sleep(5)
            result = requests.get(f"{self.base_url}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
            })

            if result.text == "CAPCHA_NOT_READY":
                continue
            if result.text.startswith("OK|"):
                return result.text.split("|", 1)[1]
            raise Exception(f"Solve failed: {result.text}")

        raise TimeoutError(f"Task {task_id} timed out")

CAPTCHA'yı yakalayan Scrapy middleware'i

Çözücü hazır olduğuna göre, onu her yanıtta otomatik çalışan bir Scrapy downloader middleware'ine (ara yazılım) bağlayın. middlewares.py dosyasını oluşturun. process_response metodu her yanıtı iki denetimden geçirir:

  • reCAPTCHAdata-sitekey özniteliğini regex ile arar ve bulursa solve_recaptcha çağırır.
  • Görüntü CAPTCHA'sıimg#captcha-image öğesindeki base64 veriyi çıkarır ve solve_image çağırır.

Her iki durumda da sonuç request.meta içine yazılır, böylece spider ona kolayca erişir.

import base64
import re
from scrapy import signals
from scrapy.http import HtmlResponse
from captcha_solver import CaptchaAISolver


class CaptchaAIMiddleware:
    """Scrapy downloader middleware that detects and solves CAPTCHAs."""

    def __init__(self, api_key):
        self.solver = CaptchaAISolver(api_key)

    @classmethod
    def from_crawler(cls, crawler):
        api_key = crawler.settings.get("CAPTCHAAI_API_KEY")
        if not api_key:
            raise ValueError("CAPTCHAAI_API_KEY setting is required")
        return cls(api_key)

    def process_response(self, request, response, spider):
        # Check for reCAPTCHA on the page
        site_key = self._find_recaptcha_key(response.text)
        if site_key:
            spider.logger.info(f"reCAPTCHA detected on {response.url}")
            token = self.solver.solve_recaptcha(site_key, response.url)
            request.meta["captcha_token"] = token
            spider.logger.info("CAPTCHA solved successfully")

        # Check for image CAPTCHA
        captcha_img = self._find_image_captcha(response)
        if captcha_img:
            spider.logger.info(f"Image CAPTCHA detected on {response.url}")
            text = self.solver.solve_image(captcha_img)
            request.meta["captcha_text"] = text
            spider.logger.info(f"Image CAPTCHA solved: {text}")

        return response

    def _find_recaptcha_key(self, html):
        match = re.search(
            r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', html
        )
        return match.group(1) if match else None

    def _find_image_captcha(self, response):
        img = response.css("img#captcha-image::attr(src)").get()
        if img and img.startswith("data:image"):
            return img.split(",", 1)[1]
        return None

settings.py yapılandırması

Middleware'i etkinleştirmek için settings.py dosyasına ekleyin. 560 öncelik değeri, middleware'i indirici zincirinde yanıt geldikten sonra çalışacak konuma yerleştirir. API anahtarınızı koda gömmeyin; bir ortam değişkeninden okuyun.

import os

CAPTCHAAI_API_KEY = os.environ.get("CAPTCHAAI_API_KEY")

DOWNLOADER_MIDDLEWARES = {
    "myproject.middlewares.CaptchaAIMiddleware": 560,
}

Örnek spider: token'ı forma enjekte etmek

Örnek bir spider, token'ın nasıl kullanılacağını gösterir. request.meta içinde bir captcha_token varsa, spider sayfayı g-recaptcha-response alanıyla bir FormRequest olarak yeniden gönderir; yoksa doğrudan ayrıştırmaya geçer. Kendi projenizde example.com yerine yalnızca yetkili olduğunuz hedef URL'yi kullanın.

import scrapy


class ProductSpider(scrapy.Spider):
    name = "products"
    start_urls = ["https://example.com/products"]

    def parse(self, response):
        # If CAPTCHA was solved, the token is in meta
        token = response.meta.get("captcha_token")
        if token:
            # Resubmit the page with the token
            yield scrapy.FormRequest(
                url=response.url,
                formdata={"g-recaptcha-response": token},
                callback=self.parse_products,
            )
        else:
            yield from self.parse_products(response)

    def parse_products(self, response):
        for product in response.css(".product-item"):
            yield {
                "name": product.css("h2::text").get(),
                "price": product.css(".price::text").get(),
                "url": response.urljoin(
                    product.css("a::attr(href)").get()
                ),
            }

        next_page = response.css("a.next-page::attr(href)").get()
        if next_page:
            yield scrapy.Request(response.urljoin(next_page))

CAPTCHA sayfalarında otomatik yeniden deneme

Bazı siteler geçersiz oturumlarda ürün içeriği yerine tam sayfa CAPTCHA döndürür. Bu durumları yakalamak için basit bir yeniden deneme middleware'i ekleyin. Yanıt gövdesinde g-recaptcha veya cf-turnstile gibi göstergeler varsa isteği en fazla üç kez yeniden kuyruğa alır.

class CaptchaRetryMiddleware:
    """Retry requests that return CAPTCHA challenge pages."""

    max_retries = 3

    def process_response(self, request, response, spider):
        if self._is_captcha_page(response):
            retries = request.meta.get("captcha_retries", 0)
            if retries < self.max_retries:
                request.meta["captcha_retries"] = retries + 1
                spider.logger.info(
                    f"CAPTCHA page detected, retry {retries + 1}"
                )
                return request.copy()

        return response

    def _is_captcha_page(self, response):
        indicators = [
            "g-recaptcha",
            "cf-turnstile",
            "captcha-image",
            "Please verify you are human",
        ]
        return any(ind in response.text for ind in indicators)

Spider'ı çalıştırın

Son olarak API anahtarınızı bir ortam değişkeni olarak dışa aktarın ve taramayı başlatın.

export CAPTCHAAI_API_KEY="YOUR_API_KEY"
scrapy crawl products -o products.json

Eşzamanlılık ve thread planlaması

CaptchaAI thread bazlı faturalandırılır: her thread aynı anda tek bir CAPTCHA çözer ve çözüm biter bitmez sıradaki göreve geçer. Çözüm başına ücret ya da günlük kota yoktur. Bu, Scrapy'nin CONCURRENT_REQUESTS ayarıyla doğrudan ilişkilidir — aynı anda çok sayıda CAPTCHA'lı sayfa işlemeyi planlıyorsanız, plan thread sayınız bu eşzamanlılığı karşılamalıdır.

Tarama hacminize göre bir başlangıç noktası:

  • BASIC ($15/ay, 5 thread) — küçük tarama işleri ve düşük eşzamanlılık için çoğu zaman yeterlidir.
  • STANDARD ($30/ay, 15 thread) — orta ölçekli, düzenli taramalar.
  • ADVANCE ($90/ay, 50 thread) — yoğun, paralel taramalar.

Fiyatlar USD üzerinden sabittir; TL kurundaki dalgalanmadan etkilenmeyen öngörülebilir aylık maliyet, Türkiye'deki otomasyon ekipleri için pratik bir avantajdır. reCAPTCHA v2 çözümleri genellikle sayfa başına 5–15 saniye sürdüğünden, CONCURRENT_REQUESTS değerini makul tutarak CAPTCHA'sız sayfaları beklemeye takılmadan taramaya devam edebilirsiniz.

Yetkili kullanım ve KVKK notu

Otomatik veri kazıma her zaman kaynak sitenin kullanım şartları ve ilgili mevzuat çerçevesinde yapılmalıdır. Üretime almadan önce şu üç noktayı gözden geçirin:

  • Türkiye'de topladığınız veriler kişisel veri içeriyorsa KVKK (Kişisel Verilerin Korunması Kanunu) kapsamına girer.
  • CaptchaAI'yi yalnızca yetkili olduğunuz QA ve veri toplama iş akışlarında kullanın.
  • Örneklerdeki example.com gibi yer tutucu adresleri kendi izinli hedeflerinizle değiştirin.

Bu çerçeveyi baştan kurmak, hem yasal hem operasyonel açıdan taramanızı sürdürülebilir kılar.

Sorun giderme

Sorun Sebep Düzeltme
ValueError: CAPTCHAAI_API_KEY setting is required Ortam değişkeni tanımlı değil CAPTCHAAI_API_KEY değişkenini ayarlayın
CAPTCHA algılanmıyor Sayfanın HTML yapısı farklı Middleware'deki data-sitekey regex desenini güncelleyin
Çözüm sırasında TimeoutError Yavaş çözüm veya ağ gecikmesi Çözücüdeki zaman aşımı değerini artırın
Spider çözümden sonra engelleniyor IP tabanlı engelleme Genel bir proxy yapılandırması ekleyin

Sık sorulan sorular

Scrapy'nin CONCURRENT_REQUESTS ayarı ile thread sayısı nasıl eşleşir?

Her eşzamanlı CAPTCHA çözümü bir thread kullanır. Aynı anda çok sayıda CAPTCHA'lı sayfa işliyorsanız, CONCURRENT_REQUESTS değerini plan thread sayınızı aşmayacak şekilde ayarlayın; aksi halde istekler kuyruğa girer ve bekler.

CaptchaAI hangi CAPTCHA türlerini çözer?

reCAPTCHA v2 ve v3, Cloudflare Turnstile, GeeTest v3, görüntü/OCR, grid ve BLS CAPTCHA'ları genel kullanımda desteklenir; CaptchaFox, Friendly Captcha ve Lemin ise beta aşamasındadır. hCaptcha ve FunCaptcha (Arkose Labs) şu anda desteklenmez, GeeTest v4 için destek çok yakında. Bu middleware'i Turnstile veya GeeTest v3 için genişletmek isterseniz process_response içine ilgili türü denetleyen ek koşullar ekleyin.

reCAPTCHA v2 çözümü taramamı ne kadar yavaşlatır?

Çözüm genellikle sayfa başına 5–15 saniye sürer ve yalnızca CAPTCHA içeren sayfaları etkiler. CONCURRENT_REQUESTS sayesinde bir sayfanın çözümünü beklerken diğer sayfaları taramaya devam edebilirsiniz.

Token geçerli ama site yine de engelliyor, ne yapmalıyım?

Bu genellikle CAPTCHA'dan bağımsız, IP tabanlı bir engellemedir. Gerçekçi HTTP başlıkları gönderin, istekler arasına gecikme koyun ve gerekirse genel bir proxy yapılandırması ekleyin.

Scrapy-Splash veya Scrapy-Playwright ile çalışır mı?

Evet. JavaScript ile oluşturulan sayfalarda middleware aynı şekilde çalışır; nihai HTML yanıtını CAPTCHA öğeleri için denetler.

İlgili rehberler

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