Reklam doğrulama otomasyonunda hattı asıl durduran şey nadiren kodunuzdur; yayıncı sayfalarında beliren reCAPTCHA ve Cloudflare Turnstile ekranlarıdır. CaptchaAI bu doğrulamaları API üzerinden çözer, böylece tarayıcınız yüzlerce sayfayı gezerken doğrulama duvarına çarpıp durmaz. Aşağıda bir doğrulama işini uçtan uca, CAPTCHA çözümü dahil nasıl kuracağınızı gösteriyoruz.
Reklam doğrulaması neyi kontrol eder, CAPTCHA neden araya girer?
| Kontrol | Ne bakılır | CAPTCHA neden devreye girer |
|---|---|---|
| Reklam yerleşimi | Reklam sayfanın görünür üst bölümünde mi çıkıyor? | Otomatik sayfa ziyaretleri bot tespitini tetikler |
| Marka güvenliği | Reklam zararlı içeriğin yanında görünmüyor mu? | Toplu URL kontrolü veri kazımaya benzer |
| Görüntülenebilirlik | Reklam kullanıcıya gerçekten göründü mü? | Cloudflare, headless tarayıcıları işaretler |
| Coğrafi hedefleme | Doğru bölgede doğru reklam gösteriliyor mu? | Proxy trafiği CAPTCHA'ları tetikler |
| Rakip izleme | Rakipler aynı sayfalarda hangi reklamları veriyor? | Yüksek hacimli reklam sorguları şüphe çeker |
İstanbul'daki bir performans pazarlama ajansının müşteri bannerlarını yüzlerce haber ve e-ticaret sitesinde her sabah doğruladığını düşünün. Liste büyüdükçe sayfaların bir kısmı reCAPTCHA veya Turnstile ile yanıt verir ve manuel kontrol imkânsız hale gelir. Not: yayıncı sayfalarından toplanan içerik kişisel veri barındırıyorsa KVKK kapsamına girer — doğrulamayı yetkiniz olan alanlarla sınırlayın.
Tek sayfalık doğrulama akışını kurma
Aşağıdaki Python betiği bir yayıncı sayfasını alır, sayfada reCAPTCHA varsa solve_captcha yardımcısıyla CaptchaAI'ye gönderip token'ı geri enjekte eder, ardından reklam etiketlerini tespit eder. Yardımcı görevi in.php'ye gönderir ve sonucu res.php'den sorgular:
import requests
import time
import re
import json
import os
from datetime import datetime
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_captcha(method, params):
params["key"] = API_KEY
params["method"] = method
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(resp.text)
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 result.text.startswith("OK|"):
return result.text.split("|", 1)[1]
raise Exception(result.text)
raise TimeoutError()
def verify_ad_placement(url, session):
"""Verify ad placement on a publisher page."""
resp = session.get(url)
# Solve CAPTCHA if present
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text)
if match:
token = solve_captcha("userrecaptcha", {
"googlekey": match.group(1),
"pageurl": url,
})
resp = session.post(url, data={"g-recaptcha-response": token})
html = resp.text
# Check for ad elements
result = {
"url": url,
"timestamp": datetime.utcnow().isoformat(),
"ads_found": [],
"brand_safety": True,
"captcha_solved": match is not None,
}
# Detect ad tags
ad_patterns = [
(r'googletag\.pubads', "Google Ad Manager"),
(r'doubleclick\.net', "DFP/DoubleClick"),
(r'ad\.doubleclick', "DoubleClick"),
(r'amazon-adsystem', "Amazon Ads"),
(r'criteo\.com/.*\.js', "Criteo"),
]
for pattern, name in ad_patterns:
if re.search(pattern, html):
result["ads_found"].append(name)
# Brand safety check — flag problematic content
safety_keywords = [
"violence", "hate speech", "explicit",
"gambling", "illegal",
]
page_text = re.sub(r'<[^>]+>', '', html).lower()
for keyword in safety_keywords:
if keyword in page_text:
result["brand_safety"] = False
break
return result
def run_verification(urls, output_file="verification_report.json"):
"""Run ad verification across multiple publisher URLs."""
session = requests.Session()
session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
results = []
for i, url in enumerate(urls):
try:
result = verify_ad_placement(url, session)
results.append(result)
ads = ", ".join(result["ads_found"]) or "None"
safe = "SAFE" if result["brand_safety"] else "UNSAFE"
print(f" [{i+1}/{len(urls)}] {url}: {ads} [{safe}]")
except Exception as e:
results.append({
"url": url,
"error": str(e),
"timestamp": datetime.utcnow().isoformat(),
})
print(f" [{i+1}/{len(urls)}] {url}: ERROR - {e}")
time.sleep(2)
with open(output_file, "w") as f:
json.dump(results, f, indent=2)
# Summary
total = len(results)
safe = sum(1 for r in results if r.get("brand_safety"))
captchas = sum(1 for r in results if r.get("captcha_solved"))
errors = sum(1 for r in results if "error" in r)
print(f"\n Total: {total} | Safe: {safe} | CAPTCHAs solved: {captchas} | Errors: {errors}")
return results
# Publisher URLs to verify
publisher_urls = [
"https://publisher1.com/article/tech-news",
"https://publisher2.com/sports/latest",
"https://publisher3.com/finance/markets",
]
run_verification(publisher_urls)
Betik sonuçları verification_report.json dosyasına yazar ve her URL için bulunan reklam ağlarını, marka güvenliği durumunu ve CAPTCHA'nın çözülüp çözülmediğini raporlar.
Cloudflare korumalı yayıncılarda ölçeklendirme
Premium yayıncıların çoğu Cloudflare kullanır. Sayfa hem Turnstile widget'ıyla hem de tam doğrulama akışıyla (403 + cf-browser-verification) gelebilir; aşağıdaki fonksiyon ikisini de ele alır:
def handle_cloudflare(url, session):
"""Handle Cloudflare-protected publisher pages."""
resp = session.get(url)
if "cf-turnstile" in resp.text:
match = re.search(r'data-sitekey=["\']([^"\']+)', resp.text)
if match:
token = solve_captcha("turnstile", {
"sitekey": match.group(1),
"pageurl": url,
})
return session.post(url, data={
"cf-turnstile-response": token,
})
if resp.status_code == 403 and "cf-browser-verification" in resp.text:
data = solve_captcha("cloudflare_challenge", {
"pageurl": url,
"proxy": "user:pass@proxy:port",
"proxytype": "HTTP",
})
# Parse qa_session_cookie and use same proxy
return data
return resp
Coğrafi hedeflemeyi doğru kurma
Reklam yerleşimi bölgeye göre değişir; İzmir'den görünen reklam Frankfurt'tan görünenle aynı olmayabilir. Doğru sonucu almak için isteklerinizi hedef coğrafyadaki proxy'ler üzerinden yönlendirin ve aynı bağlamı çözüm adımına da taşıyın. CaptchaAI çözüm isteğine proxy parametreleri iletmenize olanak tanır; böylece CAPTCHA, tarayıcınızın çıktığı IP ile aynı bölgeden çözülür ve doğrulama bağlamı bozulmaz. Bölge başına ayrı bir çalışma listesi tutmak, reklam ağı imzalarını doğru bölgeye eşlemenizi ve raporlarınızı bölge bazında temiz tutmanızı sağlar.
Doğrulama işini üretimde güvenilir tutma
Yüzlerce sayfalık bir listede tek tük hatalar kaçınılmazdır: bir sayfa zaman aşımına uğrar, bir CAPTCHA beklenenden yavaş çözülür ya da yayıncı geçici olarak 429 döndürür. İşi kırılgan bir adımlar zincirine çevirmemek için birkaç alışkanlık yeterli:
- Başarısız istekleri hemen tekrar denemek yerine üstel geri çekilme (exponential backoff) uygulayın; her denemede bekleme süresini artırın.
- Çözüm sorgusuna bir zaman aşımı koyun — örnekteki 60 sorgu × 5 saniye gibi — ve süresi dolan görevi hataya düşürüp sıradaki URL'ye geçin.
- Her URL'nin sonucunu (çözülen CAPTCHA, bulunan reklam ağları, hata mesajı) kaydedin; betikteki
verification_report.jsonçıktısı bunun için iyi bir başlangıçtır. - Aynı siteye ardışık istekleri seyreltin; istekler arasına gecikme koymak hem istek sınırlamasını hem de gereksiz CAPTCHA tetiklenmesini azaltır.
Bu dört alışkanlık, gece boyunca çalışan bir doğrulama işini sabah eksiksiz ve temiz bir raporla karşılamanızı sağlar; hatalı sayfaları ayrı bir listede toplayıp yalnızca onları yeniden çalıştırmak da toplam süreyi kısaltır.
Doğrulama hacmine göre plan seçimi
CaptchaAI thread başına faturalandırır; her thread aynı anda tek bir CAPTCHA çözer ve çözüm bitince sıradaki işi alır. Küçük listeler için BASIC ($15/ay, 5 thread) yeterlidir; onlarca yayıncıyı paralel tarıyorsanız STANDARD ($30/ay, 15 thread) veya ADVANCE ($90/ay, 50 thread) eşzamanlı çözümü artırır. Çözüm sayısı plan başına sınırsızdır. Faturalandırma USD olduğundan aylık maliyetiniz TL kurundan bağımsız kalır. Güncel fiyatlar için https://captchaai.com/pricing sayfasına bakın.
SSS
Reklam doğrulamada hangi CAPTCHA türlerini çözebilirim?
CaptchaAI reCAPTCHA v2 ve v3 (Enterprise dahil), Cloudflare Turnstile ve Challenge, GeeTest v3 ile görüntü/OCR ve grid CAPTCHA'larını çözer. Yayıncı sayfalarında en sık bunlarla karşılaşırsınız. hCaptcha ve FunCaptcha şu an desteklenmez.
Betik reklamları nasıl tespit ediyor?
Örnek, sayfa HTML'inde Google Ad Manager, DoubleClick, Amazon Ads ve Criteo gibi ağların imzalarını arar. Yeni bir ağ eklemek için ad_patterns listesine bir regex ve etiket eklemeniz yeterlidir; marka güvenliği kontrolü de aynı biçimde safety_keywords üzerinden genişletilir.
Doğrulama hacmim için kaç thread gerekir?
Thread sayısı aynı anda kaç çözümün işleneceğini belirler. Küçük ve sıralı bir liste için birkaç thread yeter; yüzlerce sayfayı paralel doğruluyorsanız daha yüksek thread'li bir plan gecikmeyi azaltır. Çözüm sayısı plan başına sınırsız olduğundan tek değişken eşzamanlılıktır.
Bu yöntem video reklam doğrulaması için de çalışır mı?
Yöntem görüntülü (display) ve yerel (native) reklamlar için uygundur. Video reklam doğrulaması genellikle Selenium veya Playwright ile gerçek tarayıcı oluşturmayı gerektirir; CAPTCHA çözümünü aynı API'yle bu akışa da eklersiniz.
Topladığım yayıncı verileri KVKK kapsamına girer mi?
Kişisel veri içeren içerik topluyorsanız KVKK yükümlülükleri geçerlidir. Doğrulamayı yetkiniz olan alanlar ve QA amaçlı akışlarla sınırlayın; CaptchaAI yalnızca sayfadaki CAPTCHA'yı çözer, veri toplama sorumluluğu sizde kalır.