Halka açık sosyal medya verisi toplayan bir araştırma işi, çoğu zaman ayrıştırma hatası yüzünden değil, akışın ortasında beliren bir doğrulama ekranı yüzünden durur. Pratik cevap şu: CAPTCHA'yı istisna olarak değil, toplayıcınızın normal bir adımı olarak modelleyin. Sayfayı alın, doğrulama var mı diye bakın, varsa token'ı API ile çözün, aynı oturum üzerinden gönderin ve kaldığınız yerden devam edin. Aşağıdaki Python iskeleti bunu yapıyor: reCAPTCHA v2, reCAPTCHA v3 ve Cloudflare Turnstile'ı CaptchaAI üzerinden çözüyor ve tek bir profil takıldığında çalışmanın tamamını durdurmuyor.
Hangi platformda hangi CAPTCHA çıkıyor
Doğrulamanın türü, toplayıcınızın hangi kod yolunu izleyeceğini belirler.
| Platform | CAPTCHA türü | Ne zaman çıkar | Bağlam |
|---|---|---|---|
| reCAPTCHA v2 | Giriş, arama, profil erişimi | İstek sınırlama | |
| reCAPTCHA v2 | Giriş, tekrarlanan aramalar | Güvenlik kontrol noktası | |
| Twitter/X | Cloudflare Turnstile | Giriş, API erişimi | Bot önleme |
| TikTok | reCAPTCHA v3 | Profil görüntüleme, arama | Trafik kalitesi puanı |
| Cloudflare doğrulama akışı | Yoğun profil gezinmesi | Bot tespiti | |
| reCAPTCHA v2 | Giriş, yoğun gezinme | Kötüye kullanım önleme |
Bu listedeki türlerin tamamı CaptchaAI tarafından destekleniyor. Kapsam dışını da baştan bilin: hCaptcha ve FunCaptcha desteklenmiyor, GeeTest v4 için yalnızca "çok yakında" ifadesi geçerli. Bir platform bu türlere geçtiyse, o kaynağı iş akışınızın kapsamından çıkarın.
Toplamaya başlamadan önce: kapsam ve KVKK
Türkiye'de çalışan bir araştırma ekibi için ilk karar teknik değil hukuki: hangi alanları topluyorsunuz ve neden. Bir profilin herkese açık olması, oradaki adın, biyografinin veya konum bilgisinin kişisel veri olmaktan çıktığı anlamına gelmez — KVKK kapsamı, verinin görünür olmasına değil, kime ait olduğuna bakar.
Pratikte üç kural işe yarıyor: alan listesini daraltın (sayım için gönderi metni yeterliyse kullanıcı adını hash'leyin), saklama süresini projenin başında sınırlayın ve platformun kullanım koşullarına uyun. CAPTCHA çözümü bir izin belgesi değil, yetkili toplama akışınızın kesintisiz çalışmasını sağlayan bir adımdır.
Toplayıcının CAPTCHA farkında iskeleti
Tasarımın özü tek bir fikirde toplanıyor: her yanıtı alırken içinde doğrulama işareti olup olmadığını kontrol edin. data-sitekey, g-recaptcha veya cf-turnstile görüyorsanız sitekey'i sayfadan okuyun, uygun method ile CaptchaAI'ye gönderin ve dönen token'ı doğru alana yazın: reCAPTCHA için g-recaptcha-response, Turnstile için cf-turnstile-response.
Sorgulama döngüsünü gerçekçi tutun: res.php yanıtı CAPCHA_NOT_READY olduğu sürece bekleyin, ama zaman aşımına düşen tek bir profil listenin geri kalanını durdurmasın. Her URL kendi try bloğunda çalışır ve sonucu success ya da failed etiketiyle raporlar.
import requests
import time
import re
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
def solve_captcha(method, sitekey, pageurl, **kwargs):
data = {
"key": CAPTCHAAI_KEY,
"method": method,
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
}
data.update(kwargs)
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
r = result.json()
if r["request"] != "CAPCHA_NOT_READY":
return r["request"]
raise TimeoutError("Solve timeout")
class SocialMediaResearcher:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 "
"Mobile/15E148 Safari/604.1",
"Accept-Language": "en-US,en;q=0.9",
})
def authenticate(self, login_url, credentials, sitekey):
"""Login with CAPTCHA handling."""
# Load login page
self.session.get(login_url)
# Solve CAPTCHA
token = solve_captcha("userrecaptcha", sitekey, login_url)
# Submit login
resp = self.session.post(login_url, data={
**credentials,
"g-recaptcha-response": token,
})
return resp.status_code == 200
def collect_profiles(self, profile_urls):
"""Collect public profile data with CAPTCHA handling."""
profiles = []
for url in profile_urls:
try:
resp = self.session.get(url, timeout=30)
# Handle CAPTCHA if triggered
if self._has_captcha(resp.text):
resp = self._handle_captcha(resp.text, url)
profiles.append({
"url": url,
"data": self._parse_profile(resp.text),
"status": "success",
})
time.sleep(5) # Slow down between profiles
except Exception as e:
profiles.append({
"url": url,
"error": str(e),
"status": "failed",
})
return profiles
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'cf-turnstile',
'challenge-platform', 'captcha',
])
def _handle_captcha(self, html, url):
match = re.search(r'data-sitekey="([^"]+)"', html)
if not match:
return self.session.get(url)
sitekey = match.group(1)
if 'cf-turnstile' in html:
token = solve_captcha("turnstile", sitekey, url)
return self.session.post(url, data={"cf-turnstile-response": token})
else:
token = solve_captcha("userrecaptcha", sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
def _parse_profile(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
return {
"name": self._safe_text(soup, "h1, .profile-name"),
"bio": self._safe_text(soup, ".bio, .profile-bio"),
"followers": self._safe_text(soup, "[data-followers], .followers"),
"posts": self._safe_text(soup, "[data-posts], .posts-count"),
}
def _safe_text(self, soup, selector):
el = soup.select_one(selector)
return el.get_text(strip=True) if el else ""
Buradaki SocialMediaResearcher sınıfı tek bir requests.Session üzerinden ilerliyor. Bunun önemi şu: çözülen token ile devam eden istek aynı oturumda olmazsa, doğrulama akışı en baştan tetiklenir ve kendinizi sonu gelmeyen bir döngüde bulursunuz.
Hashtag ve trend verisini sayfalayarak toplama
Trend araştırmasında hacim, sayfalama döngüsünden gelir — ve doğrulama genelde ikinci ya da üçüncü sayfada devreye girer. Aynı kontrol mantığını sayfa döngüsünün içine koyun, her sayfa arasına gecikme bırakın ve topladığınız metni kısaltarak saklayın; ham HTML biriktirmenin analiz açısından bir faydası yok.
def research_hashtag(hashtag, platform_url, pages=5):
"""Collect posts for a specific hashtag."""
researcher = SocialMediaResearcher(
proxy="http://user:[email protected]:5000"
)
all_posts = []
for page in range(pages):
url = f"{platform_url}/explore/tags/{hashtag}?page={page}"
resp = researcher.session.get(url, timeout=30)
if researcher._has_captcha(resp.text):
resp = researcher._handle_captcha(resp.text, url)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
posts = soup.select(".post-item, article")
for post in posts:
all_posts.append({
"text": post.get_text(strip=True)[:500],
"hashtag": hashtag,
"page": page,
})
time.sleep(5)
return all_posts
Marka anmalarını günlük taramaya bağlama
Marka takibi tekrarlanabilirlik ister: aynı anahtar kelimeler, aynı platformlar, her gün aynı saatte. Zamanlamayı Europe/Istanbul saatine göre kurun ve çıktıyı tarih damgalı JSON olarak saklayın; sayım düştüğünde bunun gerçek bir düşüş mü yoksa toplama hatası mı olduğunu ancak böyle ayırt edersiniz.
import json
from datetime import datetime
class BrandMonitor:
def __init__(self, brand_name, keywords, proxy=None):
self.brand = brand_name
self.keywords = keywords
self.researcher = SocialMediaResearcher(proxy=proxy)
def daily_scan(self, platform_urls):
"""Run daily brand mention scan across platforms."""
report = {
"brand": self.brand,
"date": datetime.now().isoformat(),
"platforms": {},
}
for name, url in platform_urls.items():
mentions = []
for keyword in self.keywords:
search_url = f"{url}/search?q={keyword}"
try:
resp = self.researcher.session.get(search_url, timeout=30)
if self.researcher._has_captcha(resp.text):
resp = self.researcher._handle_captcha(
resp.text, search_url,
)
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
results = soup.select(".search-result, .post")
mentions.append({
"keyword": keyword,
"count": len(results),
})
time.sleep(5)
except Exception as e:
mentions.append({
"keyword": keyword,
"error": str(e),
})
report["platforms"][name] = mentions
return report
# Usage
monitor = BrandMonitor(
brand_name="CaptchaAI",
keywords=["captchaai", "captcha ai", "captcha solver"],
proxy="http://user:[email protected]:5000",
)
report = monitor.daily_scan({
"twitter": "https://twitter-alternative.example.com",
"reddit": "https://www.reddit.com",
})
print(json.dumps(report, indent=2))
Anahtar kelime başına hata alanını raporda tutmak sessiz veri kaybını önler: üst üste failed görüyorsanız sorun genellikle çözümde değil istek ritmindedir.
İstek hızı ve oturum bütçesi
Toplama hızını CAPTCHA'ya rağmen değil, CAPTCHA'yı hesaba katarak planlayın. Aşağıdaki değerler saha gözlemlerine dayanır ve platform davranışına göre değişebilir; kendi ölçümünüzle güncelleyin.
| Platform | Güvenli istek aralığı | Oturum uzunluğu |
|---|---|---|
| 10 saniyede 1 istek | En fazla 5 dakika, sonra ara verin | |
| 5 saniyede 1 istek | En fazla 10 dakika | |
| Twitter/X | 3 saniyede 1 istek | En fazla 15 dakika |
| TikTok | 5 saniyede 1 istek | En fazla 5 dakika |
| 10 saniyede 1 istek | En fazla 5 dakika | |
| 2 saniyede 1 istek | En fazla 30 dakika |
Proxy kullanıyorsanız çıkış noktasını araştırdığınız kitlenin bölgesiyle tutarlı tutun ve Accept-Language başlığını aynı bölgeye göre ayarlayın; içerik farklılıkları çoğu zaman engellemeden değil, bölgesel varyasyondan kaynaklanır. Ayrıntılı yapılandırma için proxy kullanımı ve çözüm başarısı rehberine bakabilirsiniz.
Eşzamanlılık ve maliyet: hangi plan yeter?
CaptchaAI thread tabanlı faturalandırılır: bir thread, aynı anda işlenen tek bir CAPTCHA demektir ve plan içindeki çözüm sayısı sınırsızdır. Yani maliyeti belirleyen soru "kaç CAPTCHA çözeceğim" değil, "aynı anda kaç tanesini bekleteceğim".
Hesabı en kötü durum üzerinden yapın: Cloudflare Turnstile 10 saniyenin altında, reCAPTCHA v3 4 saniyenin altında temizlenir, reCAPTCHA v2 için tavan 60 saniyedir. Tek makineli günlük bir marka taraması genellikle BASIC ($15/ay, 5 thread) ile döner; paralel platform taraması için STANDARD ($30/ay, 15 thread), üretim ölçekli bir pipeline için ADVANCE ($90/ay, 50 thread) uygundur.
Türkiye'deki ekipler için ek bir avantaj var: fiyat USD üzerinden ve aylık sabittir. Çözüm başına ücretlendirmede hacim arttıkça bütçe kayarken, thread tabanlı planda ay başında bildiğiniz rakam ay sonunda da aynıdır.
Sorun giderme
| Sorun | Olası sebep | Ne yapmalı |
|---|---|---|
| Her istekte CAPTCHA çıkıyor | Çıkış IP'niz işaretlenmiş | İstek aralığını artırın, çıkış noktanızı ve oturum uzunluğunu yeniden yapılandırın |
| Boş sayfa dönüyor | İçerik giriş adımının arkasında | Önce kimlik doğrulamasını tamamlayın, sonra profil isteklerine geçin |
| Doğrulama akışı döngüye giriyor | Token farklı bir oturumdan gönderiliyor | Aynı requests.Session üzerinden devam edin |
| Token çözüldü ama reddedildi | Token'ın süresi doldu ya da sitekey eski | sitekey'i sayfadan yeniden okuyun ve token'ı çözümden hemen sonra gönderin |
| Tarayıcıdaki içerikten farklı sonuç | Bölge ve dil farkı | Accept-Language değerini ve çıkış bölgesini hedef kitleyle eşleştirin |
Oturumların birden fazla çalıştırma boyunca ayakta kalması gerekiyorsa tarayıcı oturumu kalıcılığı rehberi ve tarayıcı profili izolasyonu ile CaptchaAI entegrasyonu bu iskeletin doğal devamıdır.
Sık sorulan sorular
CaptchaAI hangi CAPTCHA türlerini çözüyor, hCaptcha destekleniyor mu?
hCaptcha ve FunCaptcha desteklenmiyor; GeeTest v4 için yalnızca "çok yakında" ifadesi geçerli. Bu iş akışında geçen reCAPTCHA v2 (görünmez ve Enterprise varyantları dâhil), reCAPTCHA v3, Cloudflare Turnstile, Cloudflare doğrulama akışı ve GeeTest v3 destekleniyor. CaptchaFox (beta), Friendly Captcha (beta) ve Lemin (beta) ise beta aşamasındadır.
Araştırma projem için kaç thread gerekir?
Eşzamanlı olarak beklettiğiniz CAPTCHA sayısı kadar. "Aynı anda kaç toplayıcı işçim doğrulama bekliyor?" sorusunu yanıtlayın: beş paralel işçilik bir tarama BASIC ($15/ay, 5 thread) ile başlar, kuyrukta bekleme süresi büyümeye başladığında bir üst plana geçin.
Token'ı hangi alana yazmam gerekiyor?
reCAPTCHA ailesinde g-recaptcha-response, Cloudflare Turnstile'da cf-turnstile-response. Alan adlarını karıştırmak, çözüm doğru olsa bile isteğin reddedilmesinin en sık sebebidir. Token'ı aldıktan sonra bekletmeyin — kısa ömürlüdür ve süresi dolan bir token yeniden çözüm gerektirir.
Topladığım profil verileri KVKK kapsamına girer mi?
Kişiyi doğrudan ya da dolaylı tanımlıyorsa evet; verinin herkese açık olması bunu değiştirmez. Gerekçenizi belgeleyin, gereksiz alanları hiç almayın ve yalnızca toplam sayım üretecekseniz kimlik alanlarını toplama anında anonimleştirin.
İlgili kılavuzlar
- Proxy kullanımı ve çözüm başarısı
- Tarayıcı oturumu kalıcılığı
- Tarayıcı profili izolasyonu ve CaptchaAI entegrasyonu
Araştırma toplayıcınızın doğrulama adımını çalışır hâle getirin — CaptchaAI anahtarınızı alın ve platform CAPTCHA'larını otomatik çözüme bağlayın.