Bir Python kazıyıcısında CAPTCHA'yla karşılaştığınızda çoğu zaman Selenium'a ya da tam bir tarayıcıya ihtiyacınız yoktur: sitekey'i sayfadan çeker, CaptchaAI API'sine gönderir ve dönen token'ı forma enjekte edersiniz. Bu rehber, requests ve BeautifulSoup tabanlı kazıyıcılarınıza bu akışı uçtan uca nasıl ekleyeceğinizi — yeniden kullanılabilir bir çözücü sınıfından üretim için hata yönetimine kadar — gösterir. reCAPTCHA v2/v3, Cloudflare Turnstile ve resim tabanlı CAPTCHA'lar aynı deseni paylaşır; farklı olan yalnızca gönderdiğiniz method parametresidir.
Gereksinimler
Başlamadan önce ortamınızda şunların hazır olması yeterlidir:
| Gereksinim | Ayrıntılar |
|---|---|
| Python 3.7+ | pip ile kurulu |
| requests | pip install requests |
| beautifulsoup4 | pip install beautifulsoup4 |
| CaptchaAI API anahtarı | captchaai.com üzerinden alın |
API anahtarınızı kontrol panelinden kopyalayın ve kod içine sabitlemek yerine bir ortam değişkeninde tutun.
Yeniden kullanılabilir CaptchaAI çözücü sınıfı
Akışın kalbi tek bir yardımcı sınıftır: bir görevi in.php uç noktasına gönderir, sonucu res.php üzerinden sorgular ve token hazır olduğunda döndürür. Bu sınıfı bir kez yazın, tüm kazıyıcılarınızda yeniden kullanın:
import requests
import time
class CaptchaSolver:
def __init__(self, api_key):
self.api_key = api_key
self.base = "https://ocr.captchaai.com"
def _submit(self, params):
params["key"] = self.api_key
resp = requests.get(f"{self.base}/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(f"Submit error: {resp.text}")
return resp.text.split("|")[1]
def _poll(self, task_id, timeout=300):
deadline = time.time() + timeout
while time.time() < deadline:
time.sleep(5)
resp = requests.get(f"{self.base}/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id
})
if resp.text == "CAPCHA_NOT_READY":
continue
if resp.text.startswith("OK|"):
return resp.text.split("|")[1]
raise Exception(f"Solve error: {resp.text}")
raise TimeoutError("Solve timed out")
def solve_recaptcha_v2(self, site_key, page_url):
task_id = self._submit({
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url
})
return self._poll(task_id)
def solve_recaptcha_v3(self, site_key, page_url, action="verify"):
task_id = self._submit({
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"version": "v3",
"action": action
})
return self._poll(task_id)
def solve_turnstile(self, site_key, page_url):
task_id = self._submit({
"method": "turnstile",
"sitekey": site_key,
"pageurl": page_url
})
return self._poll(task_id)
def solve_image(self, image_base64):
task_id = self._submit({
"method": "base64",
"body": image_base64
})
return self._poll(task_id)
_poll metodu her beş saniyede bir sonucu sorgular ve varsayılan 300 saniyelik zaman aşımına kadar bekler. reCAPTCHA v3 için action değerini sayfadaki gerçek eylem adıyla eşleştirin; yanlış eylem, çözülen token'ın site tarafından reddedilmesine yol açar.
reCAPTCHA korumalı bir formu kazıma
Tipik akış beş adımdır: sayfayı yükleyin, sitekey'i çıkarın, CAPTCHA'yı çözün, token'ı forma ekleyin ve sonucu ayrıştırın. Aşağıdaki örnek, arama formu reCAPTCHA v2 ile korunan bir sayfada bu adımları uygular:
from bs4 import BeautifulSoup
import requests
solver = CaptchaSolver("YOUR_API_KEY")
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
# Step 1: Load the page
url = "https://example.com/search"
page = session.get(url)
soup = BeautifulSoup(page.text, "html.parser")
# Step 2: Extract the site key
recaptcha_div = soup.find("div", class_="g-recaptcha")
site_key = recaptcha_div["data-sitekey"]
# Step 3: Solve the CAPTCHA
token = solver.solve_recaptcha_v2(site_key, url)
# Step 4: Submit the form with the token
form_data = {
"q": "search term",
"g-recaptcha-response": token
}
result = session.post(url, data=form_data)
# Step 5: Parse the results
result_soup = BeautifulSoup(result.text, "html.parser")
items = result_soup.find_all("div", class_="result-item")
for item in items:
print(item.text.strip())
Kritik nokta 4. adımdır: token, formun beklediği g-recaptcha-response alanına yerleştirilmelidir. Alan adı farklıysa gönderim sessizce başarısız olur ve site CAPTCHA sayfasını yeniden döndürür. Oturum boyunca çerezleri korumak için tüm isteklerde aynı requests.Session() nesnesini kullanın.
Sayfalandırılmış sonuçları toplu kazıma
CAPTCHA'nın ardındaki çok sayfalı listelerde her sayfa için ayrı bir token gerekebilir. Aşağıdaki fonksiyon sayfaları sırayla dolaşır, boş sonuç geldiğinde durur ve istekler arasına kibar bir gecikme koyar:
def scrape_all_pages(base_url, site_key, max_pages=10):
solver = CaptchaSolver("YOUR_API_KEY")
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
all_results = []
for page_num in range(1, max_pages + 1):
page_url = f"{base_url}?page={page_num}"
# Solve CAPTCHA for each page if needed
token = solver.solve_recaptcha_v2(site_key, page_url)
resp = session.get(page_url, params={
"g-recaptcha-response": token,
"page": page_num
})
soup = BeautifulSoup(resp.text, "html.parser")
items = soup.find_all("div", class_="item")
if not items:
break
all_results.extend([item.text.strip() for item in items])
print(f"Page {page_num}: {len(items)} items")
time.sleep(2) # Polite delay
return all_results
Her sayfa için ayrı bir çözüm istediğinizde eşzamanlı thread sayınız doğrudan verimi belirler — CaptchaAI planları tam da bu eşzamanlılık üzerinden faturalandırılır (aşağıdaki maliyet bölümüne bakın).
Resim tabanlı CAPTCHA'ları çözme
Bazı siteler reCAPTCHA yerine klasik, metin içeren resim CAPTCHA'ları kullanır. Bu durumda resmi indirir, base64'e kodlar ve solve_image ile gönderirsiniz:
import base64
def scrape_with_image_captcha(url):
solver = CaptchaSolver("YOUR_API_KEY")
session = requests.Session()
page = session.get(url)
soup = BeautifulSoup(page.text, "html.parser")
# Find the CAPTCHA image
captcha_img = soup.find("img", {"id": "captcha-image"})
captcha_url = captcha_img["src"]
# Download and encode the image
img_resp = session.get(captcha_url)
img_base64 = base64.b64encode(img_resp.content).decode()
# Solve
captcha_text = solver.solve_image(img_base64)
# Submit
form_data = {
"captcha": captcha_text,
"username": "user"
}
result = session.post(url, data=form_data)
return result.text
Üretim için hata yönetimi ve yeniden deneme
Gerçek kazıyıcılarda ağ hataları ve geçici çözüm hataları kaçınılmazdır. Çözüm çağrısını yeniden deneme mantığıyla sarın; birkaç deneme sonrası hâlâ başarısızsa hatayı yukarı taşıyın:
def solve_with_retry(solver, site_key, page_url, max_retries=3):
for attempt in range(max_retries):
try:
return solver.solve_recaptcha_v2(site_key, page_url)
except Exception as e:
if attempt == max_retries - 1:
raise
print(f"Attempt {attempt + 1} failed: {e}. Retrying...")
time.sleep(2)
Daha sağlam bir üretim iş akışı için üstel geri çekilme (exponential backoff) ekleyin ve kalıcı olarak başarısız olan görevleri loglayın.
Sorun giderme
En sık karşılaşılan hatalar ve çözümleri:
| Sorun | Sebep | Düzeltme |
|---|---|---|
ERROR_WRONG_USER_KEY |
Geçersiz API anahtarı | Anahtarı kontrol panelinden doğrulayın |
ERROR_ZERO_BALANCE |
Bakiye yok | Hesabınızı doldurun |
| Form gönderimi CAPTCHA sayfasını yeniden döndürüyor | Token'ın süresi dolmuş veya alan adı yanlış | Token'ı hemen kullanın; form alan adlarını kontrol edin |
ConnectionError |
Ağ sorunu | Üstel geri çekilmeli yeniden deneme mantığı ekleyin |
| Gönderimden sonra boş sonuç | Site çerez/oturum gerektiriyor | Çerezleri korumak için requests.Session() kullanın |
Ölçeklendirme, maliyet ve KVKK
CaptchaAI thread bazlı faturalandırır: BASIC ($15/ay, 5 thread) küçük kazıma işleri için yeterlidir; eşzamanlı hacminiz arttıkça ADVANCE ($90/ay, 50 thread) gibi üst planlara geçebilirsiniz. Türkiye'deki geliştiriciler için USD bazlı sabit aylık ücret, TL dalgalanmasından bağımsız öngörülebilir bir maliyet anlamına gelir; her thread aylık sınırsız çözüm içerir, yani ödediğiniz şey görev başına değil, eşzamanlılıktır.
Yüksek hacimli işlerde istekleri sırayla beklemek yerine eşzamanlı çalıştırmak verimi ciddi biçimde artırır; aiohttp ile CaptchaAI API'sini birlikte kullanan asenkron entegrasyon rehberine bakın. Aynı IP'den yoğun istek engellenmeye yol açabileceğinden, istekler arasına gecikme koyun ve farklı çıkış IP'leri için proxy yapılandırması rehberini inceleyin.
Son olarak yasal çerçeveyi unutmayın: kazıdığınız veriler kişisel veri içeriyorsa KVKK (Kişisel Verilerin Korunması Kanunu) kapsamına girer. CaptchaAI'yi yalnızca yetkili olduğunuz kaynaklarda ve izinli QA/veri toplama iş akışları çerçevesinde kullanın.
SSS
Bu yöntem hangi CAPTCHA türlerini çözer?
CaptchaAI; reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3 ve resim/OCR tabanlı CAPTCHA'ları çözer. hCaptcha ve FunCaptcha (Arkose Labs) desteklenmez; bu türler için kod deseni farklıdır ve bir çözüm sağlamaz.
reCAPTCHA v3 skoru düşük gelirse ne yapmalıyım?
Önce action değerinin sayfadaki gerçek eylem adıyla birebir eşleştiğinden emin olun; yanlış eylem token'ın reddedilmesine ya da düşük skora yol açar. Token'ı ürettikten hemen sonra, gecikmeden gönderin.
Token'ı aldıktan sonra form neden yine CAPTCHA döndürüyor?
Genellikle iki nedenden: token'ın süresi dolmuştur (birkaç dakikada geçersizleşir) ya da yanlış form alanına yerleştirilmiştir. Token'ı g-recaptcha-response alanına koyduğunuzu ve aynı oturumu kullandığınızı doğrulayın.
Kazıma için hangi CaptchaAI planı yeterli?
Tek thread'le sıralı çalışan küçük kazıyıcılar için BASIC ($15/ay, 5 thread) yeterlidir. Çok sayfayı eşzamanlı çözüyorsanız thread sayısı verimi belirler; ADVANCE ($90/ay, 50 thread) daha yüksek eşzamanlılık sağlar. Güncel fiyatlar için captchaai.com/pricing sayfasına bakın.
Kazıdığım veriler KVKK'ya tabi mi?
Veriler gerçek kişilere ait bilgiler içeriyorsa evet, KVKK kapsamındadır. Yalnızca erişim yetkiniz olan kaynaklarda ve meşru bir işleme amacı çerçevesinde çalışın; kişisel veriyi gereksiz yere toplamayın.