Use Cases

CAPTCHA İşleme ile Etkinlik Bileti İzleme

Bir bilet sitesinin müsaitlik durumunu birkaç dakikada bir kontrol eden bir monitör yazmak aslında kolaydır; işin zor kısmı, her istekte karşınıza çıkan reCAPTCHA v2 ve Cloudflare Turnstile doğrulamalarıdır. Bu doğrulamalar çözülmediğinde monitörünüz ya boş bir sayfa okur ya da tamamen engellenir.

CaptchaAI tam bu adımı devralır: doğrulamayı API üzerinden çözer, token'ı geri verir ve monitörünüz kaldığı yerden müsaitliği okumaya devam eder. Bu rehberde, CAPTCHA çözümünü baştan sona entegre eden çalışan bir Python bilet monitörü kuracağız — konser, spor ve tiyatro etkinliklerinin müsaitliği değiştiğinde otomatik uyarı gönderen bir yapı.


Bilet siteleri neden bu kadar çok CAPTCHA gösterir?

Yüksek talepli etkinliklerde bilet sayfaları saniyede binlerce otomatik istek alır. Siteler bu yükü ayıklamak için üç katmanı birlikte kullanır:

  • reCAPTCHA v2 — kutucuk ve resim seçme doğrulaması,
  • Cloudflare Turnstile ile arkasındaki Cloudflare doğrulama akışı,
  • Aynı IP'den gelen sık isteklere uygulanan hız sınırı.

Sonuç olarak müsaitliği düzenli okumak isteyen meşru bir monitör bile bu doğrulamalarla karşılaşır. Buradaki amaç bilet "kapmak" değil, stok durumunu doğru okuyup değişimde haber vermektir — CAPTCHA'yı çözmek de bu okumanın önündeki tek teknik engeldir.


Monitör nasıl çalışır

Monitör basit bir döngü izler: yapılandırdığınız etkinlikleri sırayla kontrol eder, sayfada CAPTCHA varsa CaptchaAI ile çözer, ardından müsaitliği ayrıştırır ve durum bir öncekine göre değiştiyse uyarı gönderir.

Configure events → Check availability → CAPTCHA?
                                           ↓ Yes
                                      Solve via CaptchaAI → Retry
                                           ↓ No
                                      Parse availability → Changed?
                                                             ↓ Yes
                                                         Send alert

Başlamadan önce

Kuruluma başlamadan şunlara ihtiyacınız var:

Gereksinim Ayrıntılar
CaptchaAI API anahtarı captchaai.com
Python 3.8+ requests kütüphanesiyle
Proxy Kararlı bir çıkış IP'si önerilir
pip install requests

CAPTCHA çözücü fonksiyonu

Aşağıdaki yardımcı fonksiyon, desteklenen her yöntem için tek bir arayüz sunar: görevi in.php ucuna gönderir, sonucu res.php üzerinden sorgular ve token'ı döndürür. İlk bekleme Turnstile için 10, reCAPTCHA için 20 saniyedir; ardından beş saniyelik aralıklarla sonucu sorgulayarak yanıtı bekler.

import requests
import time

API_KEY = "YOUR_API_KEY"


def solve_captcha(method, params):
    """Generic CaptchaAI solver for any supported method."""
    params["key"] = API_KEY
    params["json"] = 1

    submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    initial_wait = 10 if method == "turnstile" else 20
    time.sleep(initial_wait)

    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")

Bilet müsaitlik monitörü

TicketMonitor sınıfı bir requests oturumu tutar, isteğe bağlı bir proxy alır ve her etkinliğin son durumunu hafızasında saklar. check_event sayfayı indirir; HTML içinde g-recaptcha görürse reCAPTCHA, cf-turnstile görürse Turnstile token'ı çözer ve formu bu token'la yeniden gönderir. Durum bir önceki kontrolden farklıysa _send_alert tetiklenir.

from datetime import datetime
import json


class TicketMonitor:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        if proxy:
            self.session.proxies = {
                "http": f"http://{proxy}",
                "https": f"http://{proxy}"
            }
        self.last_status = {}

    def check_event(self, event):
        """Check ticket availability for an event, solving CAPTCHAs if needed."""
        url = event["url"]
        response = self.session.get(url)

        # Handle CAPTCHA if detected
        if "g-recaptcha" in response.text or "recaptcha" in response.text:
            sitekey = self._extract_sitekey(response.text)
            if sitekey:
                token = solve_captcha("userrecaptcha", {
                    "method": "userrecaptcha",
                    "googlekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "g-recaptcha-response": token
                })

        elif "cf-turnstile" in response.text:
            sitekey = self._extract_turnstile_key(response.text)
            if sitekey:
                token = solve_captcha("turnstile", {
                    "method": "turnstile",
                    "sitekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "cf-turnstile-response": token
                })

        # Parse availability
        availability = self._parse_availability(response.text, event)

        # Check for changes
        event_key = event["name"]
        if event_key in self.last_status:
            if availability != self.last_status[event_key]:
                self._send_alert(event, availability)

        self.last_status[event_key] = availability
        return availability

    def _extract_sitekey(self, html):
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _extract_turnstile_key(self, html):
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _parse_availability(self, html, event):
        """Parse ticket availability. Customize per ticketing site."""
        available = "sold out" not in html.lower()
        return {
            "event": event["name"],
            "available": available,
            "checked_at": datetime.now().isoformat()
        }

    def _send_alert(self, event, availability):
        """Send availability change notification."""
        status = "AVAILABLE" if availability["available"] else "SOLD OUT"
        print(f"[ALERT] {event['name']}: {status}")

    def monitor_all(self, events):
        """Check all events and return results."""
        results = []
        for event in events:
            try:
                result = self.check_event(event)
                results.append(result)
                print(f"[OK] {event['name']}: {'available' if result['available'] else 'sold out'}")
            except Exception as e:
                print(f"[ERROR] {event['name']}: {e}")
        return results


# Usage
events = [
    {
        "name": "Concert - Madison Square Garden - Aug 15",
        "url": "https://example-tickets.com/event/12345"
    },
    {
        "name": "Basketball Finals - Game 7",
        "url": "https://example-tickets.com/event/67890"
    }
]

monitor = TicketMonitor(proxy="user:pass@proxy.example.com:8080")
results = monitor.monitor_all(events)

for r in results:
    print(json.dumps(r, indent=2))

Beklenen çıktı:

[OK] Concert - Madison Square Garden - Aug 15: available
[OK] Basketball Finals - Game 7: sold out

Çıktıda available ve sold out etiketleri her etkinliğin o anki durumunu gösterir; durum bir sonraki kontrolde değişirse _send_alert devreye girer ve size haber verir.


Zamanlanmış çalıştırma

Monitörü elle çalıştırmak yerine düzenli aralıklarla tetikleyin. Basit bir cron girdisi çoğu senaryo için yeterlidir:

# Check every 15 minutes
*/15 * * * * cd /path/to/project && python ticket_monitor.py >> /var/log/tickets.log 2>&1

Aralığı ihtiyacınıza göre ayarlayın: genel takip için 15 dakika makul bir başlangıçtır. Talebin yüksek olduğu dönemlerde daha sık kontrol daha fazla CAPTCHA anlamına gelir, bu yüzden aralığı sıklaştırdıkça thread bütçenizi de buna göre planlayın.


Hangi plan yeterli?

CaptchaAI thread tabanlı çalışır: her plan aylık sabit bir ücrete karşılık belirli sayıda eş zamanlı thread ve sınırsız çözüm verir. Tek bir etkinliği 15 dakikada bir kontrol eden bir monitör için BASIC ($15/ay, 5 thread) fazlasıyla yeterlidir. Onlarca etkinliği paralel ve sık aralıkla izliyorsanız STANDARD ($30/ay, 15 thread) ya da ADVANCE ($90/ay, 50 thread) daha rahat nefes aldırır.

Kaba bir eşleştirme şöyle:

  • Az sayıda etkinlik, seyrek kontrol → BASIC ($15/ay, 5 thread),
  • Onlarca etkinlik, sık kontrol → STANDARD ($30/ay, 15 thread),
  • Çok sayıda etkinlik, paralel ve yoğun takip → ADVANCE ($90/ay, 50 thread).

Faturalama thread başınadır, çözüm başına değil — ve fiyatlar USD üzerinden sabittir. TL'nin oynaklığına karşı öngörülebilir aylık maliyet, sık ölçekleyen ekipler için gerçek bir avantajdır.


Sorun giderme

Sorun Sebep Çözüm
Her kontrolde sık CAPTCHA Aynı IP, oturum sürekliliği yok Çerezleri oturumda saklayın, isteklerinizi birden fazla proxy'ye yayın
Birkaç kontrol sonra engelleme Hız sınırı Kontrol aralığını artırın, isteklerinizi dağıtın
Yanlış müsaitlik durumu Sayfa yapısı değişmiş _parse_availability yöntemini güncelleyin
Yavaş CAPTCHA çözümü Yüksek çözücü yükü Üstel geri çekilme (exponential backoff) ile yeniden deneme ekleyin

Sık sorulan sorular

Bilet izleme monitörü kurarken en sık gelen sorular ve kısa yanıtları:

CaptchaAI hangi bilet CAPTCHA türlerini çözer?

reCAPTCHA v2'yi (görünmez sürüm dahil), reCAPTCHA v3'ü, Cloudflare Turnstile'ı, Cloudflare doğrulama akışını ve GeeTest v3'ü çözer. Bazı siteler hCaptcha kullanır; CaptchaAI hCaptcha'yı çözmez, bu yüzden hedef sitenizin hangi türü gösterdiğini önceden kontrol edin.

Monitörüm birkaç kontrolden sonra engelleniyor, ne yapmalıyım?

Genellikle sebep çok sık istek veya oturum sürekliliğinin olmamasıdır. Şu üç ayarı sırayla deneyin:

  • Kontrol aralığını açın (örneğin 5 dakikadan 15 dakikaya),
  • Çerezleri oturumda taşıyarak süreklilik sağlayın,
  • İsteklerinizi birden fazla proxy'ye yayın.

Doğrulama sıklığı hâlâ artıyorsa aralığı geçici olarak yükseltmek en hızlı çözümdür.

Sanal bekleme odası sayfalarını CaptchaAI çözer mi?

Hayır. Sanal bekleme odaları CAPTCHA değildir; sıraya dayalı kuyruk sistemleridir. Monitörünüz kuyruk sayfasını tanımalı ve beklemeli ya da yeniden denemelidir. CaptchaAI yalnızca kuyruğun ardından beliren CAPTCHA'yı çözer.

Bilet takibi için hangi CaptchaAI planı yeterli?

Tek bir etkinliği seyrek aralıklarla izliyorsanız BASIC ($15/ay, 5 thread) yeterlidir. Onlarca etkinliği paralel ve sık kontrol ediyorsanız STANDARD ($30/ay, 15 thread) ya da ADVANCE ($90/ay, 50 thread) daha rahattır; unutmayın, faturalama thread başınadır.

Bilet sitelerini izlemek KVKK açısından sorun yaratır mı?

Genel müsaitlik durumunu okumak, kişisel veri toplamaktan farklıdır. Yalnızca herkese açık stok bilgisini izlediğiniz sürece kişisel veri işlemezsiniz; kullanıcı bilgisi topladığınız anda KVKK kapsamına girersiniz. Her koşulda hedef sitenin kullanım şartlarına ve yetkili kullanım sınırlarına uyun.


CaptchaAI API anahtarınızı alın

Bilet müsaitliğini izlemeye captchaai.com üzerinden ücretsiz hesap açarak başlayın. API anahtarınızı alın, örnek monitörü kendi etkinlik listenize uyarlayın ve CAPTCHA'ları arka planda otomatik çözün.


İlgili rehberler

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