Haber ve medya sitelerinden başlık, özet ve meta veri toplayan bir iş akışı kurarken karşınıza çıkan ilk gerçek engel CAPTCHA'dır: Cloudflare Turnstile, reCAPTCHA v2 ve v3 sık sık devreye girip toplamayı durdurur. Bu rehber; medya izleme ekipleri, halkla ilişkiler ajansları ve araştırma birimleri için bu CAPTCHA'ları CaptchaAI API ile çözüp toplamayı kesintisiz sürdüren çalışan bir Python iş akışını gösterir. Türkiye'de içerik izleyen ekipler için bir not: kazınan metinde kişisel veri varsa süreç KVKK kapsamına girer, bu yüzden örnekler yalnızca başlık ve meta veri toplama ve yetkili olduğunuz içeriğe erişme çerçevesinde ilerler.
Haber sitelerinde hangi CAPTCHA türleriyle karşılaşırsınız?
Toplama hedefinize göre farklı doğrulama türleri devreye girer. Büyük yayıncılar çoğunlukla Cloudflare Turnstile ile, haber ajansları ve yerel siteler ise reCAPTCHA ile korunur. Aşağıdaki tablo, kaynak türüne göre ne beklemeniz gerektiğini özetler:
| Kaynak türü | CAPTCHA türü | Tetikleyici | Korunan içerik |
|---|---|---|---|
| Büyük haber yayıncıları | Cloudflare Turnstile | Bot tespiti | Makaleler, başlıklar |
| Haber ajansları (AP, Reuters) | reCAPTCHA v2 | Toplu erişim | Son dakika haberleri |
| Ödeme duvarlı yayınlar | reCAPTCHA v3 | Erişim denemeleri | Premium makaleler |
| Yerel haber siteleri | reCAPTCHA v2 | İstek sınırlama | Bölgesel haberler |
| Haber toplayıcılar | Cloudflare doğrulama akışı | Kazıma tespiti | Toplu feed'ler |
| Basın bülteni siteleri | Resim CAPTCHA'sı | İndirme sayfaları | Halkla ilişkiler içeriği |
Toplama iş akışını CaptchaAI'ye bağlayın
Aşağıdaki NewsAggregator sınıfı, her isteğin yanıtını CAPTCHA açısından kontrol eder. Bir data-sitekey, g-recaptcha veya cf-turnstile işareti bulursa görevi CaptchaAI'ye gönderir, dönen token'ı ilgili alana (g-recaptcha-response ya da cf-turnstile-response) yerleştirip isteği yeniden dener. Böylece başlık toplama ve tam makale çekme adımları, CAPTCHA çıktığında kendiliğinden devam eder.
import requests
import time
import re
from bs4 import BeautifulSoup
from datetime import datetime
import json
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("Timeout")
class NewsAggregator:
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 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
})
def collect_headlines(self, source_url, section=None):
"""Collect headlines from a news source."""
url = f"{source_url}/{section}" if section else source_url
resp = self.session.get(url, timeout=30)
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, url)
soup = BeautifulSoup(resp.text, "html.parser")
articles = []
for item in soup.select("article, .story, .headline-item, h2 a, h3 a"):
link = item if item.name == "a" else item.select_one("a")
if link:
articles.append({
"title": link.get_text(strip=True),
"url": self._abs_url(source_url, link.get("href", "")),
"source": source_url,
"collected_at": datetime.now().isoformat(),
})
return articles
def get_article(self, article_url):
"""Fetch full article content."""
resp = self.session.get(article_url, timeout=30)
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, article_url)
soup = BeautifulSoup(resp.text, "html.parser")
# Remove unwanted elements
for tag in soup.select("script, style, nav, footer, .ad, .sidebar"):
tag.decompose()
content_el = soup.select_one(
"article, .article-body, .story-body, .entry-content"
)
return {
"url": article_url,
"title": self._text(soup, "h1, .article-title"),
"author": self._text(soup, ".author, .byline, [rel='author']"),
"date": self._text(soup, "time, .publish-date, .article-date"),
"content": content_el.get_text(separator="\n", strip=True) if content_el else "",
"word_count": len(content_el.get_text().split()) if content_el else 0,
}
def aggregate_sources(self, sources, max_articles_per=20):
"""Aggregate headlines across multiple sources."""
all_articles = []
for source in sources:
try:
articles = self.collect_headlines(source["url"], source.get("section"))
all_articles.extend(articles[:max_articles_per])
print(f"{source['name']}: {len(articles)} headlines")
except Exception as e:
print(f"{source['name']}: Error - {e}")
time.sleep(3)
return all_articles
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'cf-turnstile',
])
def _solve_and_retry(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})
token = solve_captcha("userrecaptcha", sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
def _text(self, soup, selector):
el = soup.select_one(selector)
return el.get_text(strip=True) if el else ""
def _abs_url(self, base, href):
if href.startswith("http"):
return href
return base.rstrip("/") + "/" + href.lstrip("/")
# Usage
aggregator = NewsAggregator(
proxy="http://user:pass@residential.proxy.com:5000"
)
sources = [
{"name": "Tech News A", "url": "https://technews-a.example.com", "section": "latest"},
{"name": "Business B", "url": "https://business-b.example.com", "section": "tech"},
{"name": "Industry C", "url": "https://industry-c.example.com"},
]
headlines = aggregator.aggregate_sources(sources)
print(f"Total: {len(headlines)} headlines collected")
Token hangi alana yerleşir?
_solve_and_retry metodu, çözülen değeri CAPTCHA türüne göre doğru alana yazar: Cloudflare Turnstile için cf-turnstile-response, reCAPTCHA için g-recaptcha-response. Ayrımı, sayfadaki cf-turnstile işaretine bakarak otomatik yapar; siz yalnızca kaynak listesini verirsiniz.
Anahtar kelimeye göre haber izleme
Belirli konuları takip etmek istiyorsanız, toplanan başlıkları bir anahtar kelime listesine göre süzebilirsiniz. NewsMonitor sınıfı toplayıcının üstünde çalışır: her taramada yeni başlıkları getirir, daha önce görülen URL'leri eler ve yalnızca eşleşen makaleleri döndürür. continuous_monitor ile bunu periyodik olarak çalıştırıp yeni eşleşmelerde uyarı üretebilirsiniz.
class NewsMonitor:
def __init__(self, keywords, sources, proxy=None):
self.keywords = [kw.lower() for kw in keywords]
self.aggregator = NewsAggregator(proxy=proxy)
self.sources = sources
self.seen_urls = set()
def scan(self):
"""Scan for articles matching keywords."""
headlines = self.aggregator.aggregate_sources(self.sources)
matches = []
for article in headlines:
if article["url"] in self.seen_urls:
continue
title_lower = article["title"].lower()
matched_kws = [kw for kw in self.keywords if kw in title_lower]
if matched_kws:
article["matched_keywords"] = matched_kws
matches.append(article)
self.seen_urls.add(article["url"])
return matches
def continuous_monitor(self, interval_min=30):
"""Run continuous monitoring with alerts."""
while True:
matches = self.scan()
if matches:
print(f"\n=== {len(matches)} new matches found ===")
for m in matches:
print(f" [{', '.join(m['matched_keywords'])}] {m['title']}")
print(f" {m['url']}")
else:
print(f"No new matches at {datetime.now().strftime('%H:%M')}")
time.sleep(interval_min * 60)
# Monitor for specific topics
monitor = NewsMonitor(
keywords=["captcha", "bot detection", "web scraping", "automation"],
sources=sources,
proxy="http://user:pass@residential.proxy.com:5000",
)
matches = monitor.scan()
Kaynak başına tarama bütçesi planlayın
Tüm yayıncılara aynı istek hızını uygulamak hem gereksiz CAPTCHA tetikler hem de kaynakları yorar. Onun yerine her kaynağa ayrı bir tarama bütçesi tanımlayın:
- Her kaynağa güncellik ihtiyacına, CAPTCHA baskısına ve içeriğin değerine göre bir tarama sıklığı atayın.
- CAPTCHA'nın en yoğun çıktığı hassas alanlarda istek hızını düşürün; düşük riskli kaynaklarda daha hızlı ilerleyin.
- Çözülen, kaçırılan ve zaman aşımına uğrayan istekleri kaynak bazında izleyin; bütçeyi bu gerçek sinyallere göre ayarlayın.
Bu ayrım, sınırlı thread kapasitesini en çok haber üreten kaynaklara yönlendirmenizi ve düşük değerli sitelerde boşa çözüm harcamamanızı sağlar.
Doğrulama çıktığında ne yaparsınız?
Toplama sırasında en sık karşılaşılan tıkanmalar bellidir. Aşağıdaki tablo, semptomu nedeniyle ve pratik çözümüyle eşleştirir:
| Sorun | Sebep | Çözüm |
|---|---|---|
| Cloudflare tüm istekleri engelliyor | Agresif bot tespiti | Gerçekçi bir User-Agent kullanın ve istek hızını düşürün |
| Makale yerine ödeme duvarı geliyor | İçerik abonelik arkasında | Ödeme duvarını tespit edip işaretleyin; yalnızca yetkili içeriğe erişin |
| Her sayfada CAPTCHA çıkıyor | IP işaretlenmiş | İstek aralığına 5+ saniye gecikme ekleyin, istek hacmini azaltın |
| Makale içeriği boş geliyor | İçerik JavaScript ile oluşturuluyor | SPA siteleri için Selenium/Puppeteer kullanın |
| Yinelenen makaleler | Aynı haber birden çok kaynakta | Başlık benzerliğine göre tekilleştirme uygulayın |
Toplama maliyetini önceden kestirin
Haber toplama iş yükü dalgalıdır: son dakika haberlerinde eşzamanlı istek sayısı artar, sakin saatlerde düşer. CaptchaAI çözüm başına değil eşzamanlı thread başına ücretlendirdiği için aylık maliyetiniz öngörülebilir kalır — TL kurundaki dalgalanmaya karşı sabit USD fiyatlandırma, Türkiye'deki ekipler için pratik bir avantajdır. Kaç eşzamanlı isteğe ihtiyaç duyduğunuza göre bir plan seçin:
- BASIC ($15/ay, 5 thread) — birkaç kaynağı izleyen küçük projeler için yeterlidir.
- STANDARD ($30/ay, 15 thread) — düzenli çalışan, orta ölçekli çok kaynaklı hatlara uygundur.
- ADVANCE ($90/ay, 50 thread) — onlarca kaynağı sürekli tarayan yoğun iş yükleri için eşzamanlılığı rahatlatır.
Her planda thread başına çözüm sınırsızdır; hacim arttıkça sürpriz bir çözüm ücreti çıkmaz, yalnızca eşzamanlı thread sayısı maliyeti belirler.
Sık sorulan sorular
Haber sitelerindeki Cloudflare Turnstile ve reCAPTCHA'yı CaptchaAI çözer mi?
Evet. CaptchaAI reCAPTCHA v2, reCAPTCHA v3 ve Cloudflare Turnstile'ı destekler; yukarıdaki iş akışı üçünü de aynı solve_captcha çağrısıyla ele alır. Turnstile için token cf-turnstile-response, reCAPTCHA için g-recaptcha-response alanına yerleşir.
CaptchaAI hCaptcha'yı destekliyor mu?
Hayır. hCaptcha ve FunCaptcha şu anda desteklenmiyor. Bir haber sitesi bu türleri kullanıyorsa o kaynağı toplama kapsamının dışında tutun veya sitenin izin verdiği resmi bir erişim yöntemini tercih edin.
Topladığım haber içeriği KVKK ve telif açısından güvenli mi?
Başlık ve meta verilerin araştırma ya da izleme amacıyla toplanması yaygın bir uygulamadır; ancak telifli makalelerin tamamını izinsiz çoğaltmak yasaktır. Kısa alıntı kullanın ve orijinal kaynağa bağlantı verin. Kazınan metinde kişisel veri varsa süreç KVKK kapsamına girer — verileri yalnızca yetkili olduğunuz iş akışlarında işleyin.
Yüksek hacimli toplama için hangi plan uygun?
Eşzamanlı istek sayınıza bakın. Birkaç kaynağı izleyen projeler için BASIC ($15/ay, 5 thread) yeterlidir; onlarca kaynağı sürekli tarayan hatlar ADVANCE ($90/ay, 50 thread) ile daha az kuyruk bekler. Thread tabanlı model sayesinde çözüm hacmi maliyeti değiştirmez.
İlgili kılavuzlar
- Proxy yapılandırması ve CAPTCHA çözümü rehberi
- Sosyal medya araştırmasında CAPTCHA çözümü
Haberleri istediğiniz kaynaktan tek bir iş akışında toplayın — CaptchaAI anahtarınızı alın ve içerik toplamayı otomatikleştirin.