Use Cases

Uçuş Durumu İzleme için CAPTCHA Kullanımı

Bir uçuş takip panosu kurarken sizi asıl durduran şey uçuş verisinin kendisi değil, o veriye ulaşmadan önce tamamlamanız gereken doğrulama katmanıdır. Havayolu ve havaalanı portalları gerçek zamanlı bilgilerini Cloudflare Turnstile ve reCAPTCHA ile korur; aynı uç noktayı dakikada bir sorgulayan bir izleyici de bu doğrulamayı ilk tetikleyen taraftır. İyi haber şu: doğrulamayı tek bir API çağrısına indirgeyip oturum disiplinini doğru kurduğunuzda, gecikme ve iptal bildirimleri üreten kararlı bir uçuş durumu izleme hattı elde edersiniz. Bu rehber, İstanbul merkezli bir seyahat-teknoloji ekibinin ya da müşteri için otomasyon yazan bir geliştiricinin kuracağı türden bir izleyiciyi CAPTCHA tarafını çözerek baştan kurar.

Uçuş takibinde CAPTCHA nerede karşınıza çıkar

CAPTCHA rastgele belirmez; belirli davranışlara tepki verir. Aynı IP'den kısa aralıklarla gelen istekler, değişen bir User-Agent veya arama formu gönderimleri tipik tetikleyicilerdir. Hangi portal katmanının hangi doğrulamayı ürettiğini bilmek, izleyicinizi buna göre tasarlamanızı sağlar.

Portal türü CAPTCHA Tetikleyici
Havayolu uçuş durumu sayfası Cloudflare Turnstile Aynı IP'den sık istek
Havaalanı varış/kalkış panoları Cloudflare doğrulama akışı Bot tespiti
Uçuş arama motorları reCAPTCHA v2/v3 Arama formu gönderimi
Rezervasyon durumu sorgusu reCAPTCHA v2 Seyahat planı gösterilmeden önce
API hız sınırı sayfaları Özel CAPTCHA İstek sınırı aşıldıktan sonra

İzleme sıklığını ve CAPTCHA oranını dengeleyin

Kod yazmadan önce verilmesi gereken karar, uçuşu ne sıklıkla kontrol edeceğinizdir. Sıklık arttıkça daha fazla CAPTCHA tetiklenir; azaldıkça bildirimler gecikir. Aşağıdaki değerler gözlemlenen verilere ve kullanıcı raporlarına dayanır; sonuçlar ortama, hacme ve zamana göre değişebilir.

Kontrol sıklığı Tipik CAPTCHA oranı Öneri
Dakikada bir Yüksek (%50–80) Fazla agresif — aralığı büyütün
5 dakikada bir Orta (%10–30) Kritik uçuşlar için kabul edilebilir
15 dakikada bir Düşük (%5–10) Rutin izleme için iyi denge
30 dakikada bir Çok düşük (<%5) Uzun vadeli takip için ideal
Saatte bir Minimum (<%1) CAPTCHA nadiren tetiklenir

Pratik kural: kalkışa yakın kritik bir uçuşu 5 dakikada bir, birkaç saat sonrasına planlanmış rutin bir uçuşu ise 15–30 dakikada bir kontrol edin. Böylece CAPTCHA yükünü gerçekten ihtiyaç duyduğunuz uçuşlara ayırmış olursunuz.

Uçuş izleyicisinin mimarisi

Temel yapı basittir: durum sayfasını çekin, yanıtın bir CAPTCHA sayfası olup olmadığını kontrol edin, öyleyse token'ı CaptchaAI ile çözüp isteği yeniden gönderin. requests.Session() nesnesini yeniden kullanmak, çerezleri kontroller arasında koruyarak gereksiz doğrulamaları azaltır.

import requests
import time
from datetime import datetime

class FlightMonitor:
    def __init__(self, api_key):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })

    def check_flight(self, airline_url, flight_number):
        """Check flight status, handling CAPTCHAs if encountered."""
        response = self.session.get(
            f"{airline_url}/flight-status/{flight_number}"
        )

        if self._is_captcha_page(response):
            response = self._solve_and_retry(response, airline_url)

        return self._parse_flight_data(response.text)

    def _is_captcha_page(self, response):
        return (
            response.status_code == 403 or
            "cf-turnstile" in response.text or
            "g-recaptcha" in response.text
        )

    def _solve_and_retry(self, response, url):
        import re

        # Detect CAPTCHA type
        if "cf-turnstile" in response.text:
            match = re.search(r'data-sitekey="(0x[^"]+)"', response.text)
            token = self._solve_turnstile(match.group(1), url)
            field = "cf-turnstile-response"
        else:
            match = re.search(r'data-sitekey="([^"]+)"', response.text)
            token = self._solve_recaptcha(match.group(1), url)
            field = "g-recaptcha-response"

        return self.session.post(url, data={field: token})

    def _solve_turnstile(self, site_key, page_url):
        resp = requests.post("https://ocr.captchaai.com/in.php", data={
            "key": self.api_key,
            "method": "turnstile",
            "sitekey": site_key,
            "pageurl": page_url,
            "json": 1
        })
        task_id = resp.json()["request"]
        return self._poll_result(task_id)

    def _solve_recaptcha(self, site_key, page_url):
        resp = requests.post("https://ocr.captchaai.com/in.php", data={
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": site_key,
            "pageurl": page_url,
            "json": 1
        })
        task_id = resp.json()["request"]
        return self._poll_result(task_id)

    def _poll_result(self, task_id):
        for _ in range(60):
            time.sleep(3)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1
            })
            data = result.json()
            if data["status"] == 1:
                return data["request"]
        raise TimeoutError("CAPTCHA solve timed out")

    def _parse_flight_data(self, html):
        # Parse flight status from HTML
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")

        def text_or_none(node):
            return node.text.strip() if node and node.text else None

        return {
            "status": text_or_none(soup.select_one(".flight-status")),
            "departure": text_or_none(soup.select_one(".departure-time")),
            "arrival": text_or_none(soup.select_one(".arrival-time")),
            "gate": text_or_none(soup.select_one(".gate-info")),
            "checked_at": datetime.now().isoformat()
        }

_solve_turnstile ve _solve_recaptcha metotlarının aynı in.php / res.php akışını farklı method değerleriyle kullandığına dikkat edin: Turnstile için turnstile, reCAPTCHA için userrecaptcha. Dönen token'ı doğru alana (cf-turnstile-response veya g-recaptcha-response) yerleştirmek, isteğin kabul edilmesinin anahtarıdır.

CAPTCHA çözümüyle periyodik uçuş kontrolü

Tek bir kontrol yeterli değildir; izleyicinin belirli aralıklarla çalışıp durum değiştiğinde uyarı üretmesi gerekir. Aşağıdaki döngü, her turda CAPTCHA'yı gerektiğinde çözer, geçmişi tutar ve durum değişimini yakalar.

def monitor_flight(monitor, airline_url, flight_number, 
                   interval_seconds=300, max_checks=48):
    """Monitor a flight every N seconds, handling CAPTCHAs as needed."""
    history = []

    for check_num in range(max_checks):
        try:
            status = monitor.check_flight(airline_url, flight_number)
            history.append(status)

            # Alert on changes
            if len(history) > 1 and status["status"] != history[-2]["status"]:
                print(f"Status changed: {history[-2]['status']} → {status['status']}")

            print(f"Check {check_num + 1}: {status['status']} "
                  f"(Gate: {status.get('gate', 'Coming soon')})")

        except Exception as e:
            print(f"Check {check_num + 1} failed: {e}")

        time.sleep(interval_seconds)

    return history

# Usage
monitor = FlightMonitor("YOUR_API_KEY")
monitor_flight(monitor, "https://airline.example.com", "AA1234")

interval_seconds=300 (5 dakika) ve max_checks=48 değerleri, bir uçuşu yaklaşık dört saat boyunca izlemek için makul bir başlangıçtır. Kritik olmayan uçuşlarda aralığı büyütmek hem CAPTCHA oranını hem de portalın hız sınırına takılma riskini düşürür.

Birden fazla havayolunu paralel izleme (JavaScript)

Tek bir uçuş yerine bir pano izliyorsanız, her uçuş için ayrı durum tutmak ve çözümleri bağımsız yürütmek istersiniz. Aşağıdaki JavaScript sınıfı, uçuşları bir Map içinde tutar ve hepsini tek turda kontrol eder.

class FlightTracker {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.flights = new Map();
  }

  async addFlight(airline, flightNumber, checkUrl) {
    this.flights.set(flightNumber, {
      airline,
      url: checkUrl,
      history: [],
      lastCheck: null
    });
  }

  async checkAll() {
    const results = [];

    for (const [flightNum, flight] of this.flights) {
      try {
        const status = await this.checkFlight(flight.url, flightNum);
        flight.history.push(status);
        flight.lastCheck = new Date();
        results.push({ flight: flightNum, ...status });
      } catch (error) {
        results.push({ flight: flightNum, error: error.message });
      }
    }

    return results;
  }

  async checkFlight(url, flightNumber) {
    const response = await fetch(`${url}/status/${flightNumber}`);
    const html = await response.text();

    // Check for CAPTCHA
    if (html.includes('cf-turnstile') || response.status === 403) {
      return this.solveAndRetry(url, flightNumber, html);
    }

    return this.parseStatus(html);
  }

  async solveAndRetry(url, flightNumber, html) {
    const siteKeyMatch = html.match(/data-sitekey="(0x[^"]+)"/);
    if (!siteKeyMatch) throw new Error('No sitekey found');

    const token = await this.solveTurnstile(siteKeyMatch[1], url);

    const response = await fetch(`${url}/status/${flightNumber}`, {
      method: 'POST',
      body: new URLSearchParams({ 'cf-turnstile-response': token })
    });

    return this.parseStatus(await response.text());
  }
}

Her havayolu için ayrı oturum tutmak önemlidir: bir portalın çerezi diğerinde işe yaramaz ve karışık oturumlar gereksiz doğrulama tetikler. CaptchaAI, farklı sitelere yönelik eşzamanlı istekleri paralel çözebildiği için pano büyüdükçe darboğaz çözüm tarafında oluşmaz.

Oturumları koruyarak CAPTCHA sayısını azaltın

En verimli izleyici, en az CAPTCHA tetikleyen izleyicidir. Oturum durumunu korumak, karşılaştığınız doğrulama sayısını belirgin biçimde düşürür.

Teknik Etki
Çerezleri kontroller arasında saklayın Cloudflare qa_session_cookie çerezi 15–30 dakika geçerli kalır
Aynı User-Agent'ı koruyun UA'yı değiştirmek yeni doğrulama tetikler
Tutarlı bir IP/proxy üzerinden ilerleyin Aynı IP yeni doğrulama tetikleyicilerini azaltır
İstekleri zamana yayın Ani yoğunluk hız sınırlarını tetikler

Sık karşılaşılan sorunlar

Sorun Sebep Çözüm
Her kontrolde CAPTCHA çıkıyor Oturum korunmadı Kontroller boyunca requests.Session()'ı yeniden kullanın
Cloudflare engeli (Hata 1020) Çok fazla istek Kontrol aralığını büyütün
CAPTCHA sonrası uçuş verisi eski Çözüm sırasında token'ın süresi doldu Tam zamanında (just-in-time) çözüm kullanın
Tarayıcıdan farklı veri geliyor Eksik JavaScript oluşturma JS ağırlıklı siteler için tarayıcı otomasyonu kullanın

Kaç thread ve hangi plan: izleyicinizi ölçeklendirme

CaptchaAI thread bazlı ücretlendirir: her plan aylık sınırsız çözüm içerir ve faturayı belirleyen tek şey aynı anda kaç doğrulamanın uçuşta olabileceğidir (thread sayısı). Tek bir uçuşu 5–15 dakikada bir kontrol eden bir izleyici için BASIC ($15/ay, 5 thread) fazlasıyla yeterlidir; onlarca uçuşu paralel izleyen bir pano STANDARD ($30/ay, 15 thread) veya ADVANCE ($90/ay, 50 thread) ile rahat çalışır.

Cloudflare Turnstile tipik olarak 10 saniyenin altında, yüksek başarı oranıyla çözülür. Bu süre 5 dakikalık bir kontrol aralığının yanında ihmal edilebilir olduğundan, gerçek sınırlayıcı faktör çözüm hızı değil portalın hız sınırıdır. Türkiye'deki geliştiriciler için buradaki avantaj öngörülebilirliktir: fiyat USD ve thread başına sabit olduğu için TL kurundaki dalgalanmadan bağımsız olarak aylık maliyetiniz nettir.

Sık sorulan sorular

Turnstile çözümü ne kadar sürer, izleme aralığımı etkiler mi?

CaptchaAI, Cloudflare Turnstile'ı tipik olarak 10 saniyenin altında, yüksek başarı oranıyla çözer. Bu süre 5 dakikalık bir kontrol aralığının yanında ihmal edilebilir; yani sınırlayıcı faktör CAPTCHA çözümü değil, portalın uyguladığı hız sınırıdır.

Onlarca uçuşu paralel izlemek için hangi plan yeterli?

İhtiyacınız, aynı anda uçuşta olan doğrulama sayısına, yani thread'e bağlıdır. Birkaç uçuş için BASIC ($15/ay, 5 thread) yeterli; büyük bir pano için STANDARD ($30/ay, 15 thread) ya da ADVANCE ($90/ay, 50 thread) daha uygundur. Çözümler thread başına sınırsızdır.

"Cloudflare Hata 1020" aldığımda ne yapmalıyım?

Bu hata engellendiğiniz değil, çok sık istek gönderdiğiniz anlamına gelir. Kontrol aralığını büyütün, çerezleri kontroller arasında koruyun ve istekleri eşit aralıklara yayın; uyarı genellikle birkaç dakika içinde kalkar.

CaptchaAI hangi CAPTCHA türlerini çözer, hCaptcha dahil mi?

Uçuş portallarında en sık görülen Cloudflare Turnstile, Cloudflare doğrulama akışı ve reCAPTCHA v2/v3 desteklenir. hCaptcha ve FunCaptcha ise şu an desteklenmiyor; portalınız bunları kullanıyorsa akışı buna göre planlayın.

Uçuş verisi toplarken KVKK'ya dikkat etmeli miyim?

Uçuş durumu çoğu zaman kişisel veri içermez, ancak yolcu adı veya rezervasyon bilgisi gibi alanlara uzanıyorsanız bu veriler KVKK kapsamına girer. Yalnızca yetkiniz olan uç noktaları izleyin ve topladığınız veriyi amacına uygun kullanın.

İlgili makaleler

Sonraki adımlar

Uçuş takibinizi kırılgan adımlardan oluşan bir zincir yerine tekrarlanabilir bir iş akışına dönüştürün — CaptchaAI API anahtarınızı alın ve havayolu CAPTCHA'larını otomatik yönetin.

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