Kullanım Senaryoları

CAPTCHA İşleme ile Seyahat Ücreti Takibi

Seyahat rezervasyon siteleri, CAPTCHA'lar ve bot tespitiyle otomatik ücret kontrollerini agresif bir şekilde engelliyor. CaptchaAI bu savunmalar sayesinde uçuş ve otel fiyatlarını güvenilir bir şekilde takip etmenizi sağlar.

Seyahat Sitelerinde CAPTCHA Manzarası

Site Kategorisi CAPTCHA Türü Zorluk
Havayolları (direkt) reCAPTCHA v3, Bulut parlaması Orta
OTA'lar (Expedia, Rezervasyon) reCAPTCHA v2, Turnstile Orta-Yüksek
Meta arama (Google Uçuşlar, Kayak) reCAPTCHA v3 Orta
Ekonomik havayolları Resim CAPTCHA, reCAPTCHA Düşük-Orta
Otel toplayıcıları Cloudflare doğrulama akışı Yüksek

Ücret Monitörü Uygulaması

import requests
import time
import re
import json
import os
from datetime import datetime, timedelta

API_KEY = os.environ["CAPTCHAAI_API_KEY"]


def solve_captcha(params):
    params["key"] = API_KEY
    resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
    if not resp.text.startswith("OK|"):
        raise Exception(f"Submit: {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(f"Solve: {result.text}")
    raise TimeoutError()


class FareMonitor:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers["User-Agent"] = (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/120.0.0.0"
        )
        self.history = []

    def fetch_with_captcha(self, url):
        """Fetch a travel page, solving CAPTCHAs if encountered."""
        resp = self.session.get(url)

        # reCAPTCHA v2/v3
        match = re.search(
            r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text
        )
        if match:
            site_key = match.group(1)

            # Detect v3 vs v2
            if "recaptcha/api.js?render=" in resp.text:
                token = solve_captcha({
                    "method": "userrecaptcha",
                    "googlekey": site_key,
                    "pageurl": url,
                    "version": "v3",
                    "action": "search",
                })
            else:
                token = solve_captcha({
                    "method": "userrecaptcha",
                    "googlekey": site_key,
                    "pageurl": url,
                })

            resp = self.session.post(url, data={
                "g-recaptcha-response": token,
            })

        # Cloudflare Turnstile
        if "cf-turnstile" in resp.text:
            match = re.search(
                r'data-sitekey=["\']([^"\']+)', resp.text
            )
            if match:
                token = solve_captcha({
                    "method": "turnstile",
                    "sitekey": match.group(1),
                    "pageurl": url,
                })
                resp = self.session.post(url, data={
                    "cf-turnstile-response": token,
                })

        return resp.text

    def check_fares(self, routes):
        """Check fares for a list of routes."""
        results = []
        for route in routes:
            try:
                html = self.fetch_with_captcha(route["url"])
                prices = self._extract_prices(html)

                result = {
                    "route": f"{route['origin']}-{route['destination']}",
                    "date": route["date"],
                    "prices": prices,
                    "min_price": min(prices) if prices else None,
                    "timestamp": datetime.utcnow().isoformat(),
                }
                results.append(result)
                self.history.append(result)

                if prices:
                    print(f"  {result['route']} ({route['date']}): "
                          f"${min(prices)}-${max(prices)}")
                else:
                    print(f"  {result['route']}: No prices found")

                time.sleep(3)  # Respectful delay

            except Exception as e:
                print(f"  {route.get('origin', '?')}-"
                      f"{route.get('destination', '?')}: ERROR - {e}")

        return results

    def _extract_prices(self, html):
        """Extract prices from travel page HTML."""
        prices = []
        # Common price patterns
        for match in re.finditer(
            r'\$\s*([\d,]+(?:\.\d{2})?)', html
        ):
            price = float(match.group(1).replace(",", ""))
            if 20 < price < 10000:  # Filter noise
                prices.append(price)
        return sorted(set(prices))

    def detect_price_ürün lansmanları(self, threshold_pct=5):
        """Detect significant price ürün lansmanları in history."""
        route_prices = {}
        for entry in self.history:
            key = f"{entry['route']}_{entry['date']}"
            if key not in route_prices:
                route_prices[key] = []
            if entry["min_price"]:
                route_prices[key].append(entry["min_price"])

        alerts = []
        for key, prices in route_prices.items():
            if len(prices) >= 2:
                prev = prices[-2]
                current = prices[-1]
                change_pct = ((current - prev) / prev) * 100
                if change_pct < -threshold_pct:
                    alerts.append({
                        "route": key,
                        "previous": prev,
                        "current": current,
                        "change": f"{change_pct:.1f}%",
                    })

        return alerts

    def export_report(self, filename="fare_report.json"):
        """Export fare history to JSON."""
        with open(filename, "w") as f:
            json.dump(self.history, f, indent=2)
        print(f"Exported {len(self.history)} fare checks to {filename}")


# Define routes to monitor
routes = [
    {
        "origin": "JFK",
        "destination": "LAX",
        "date": "2025-03-15",
        "url": "https://example-airline.com/flights?from=JFK&to=LAX&date=2025-03-15",
    },
    {
        "origin": "SFO",
        "destination": "ORD",
        "date": "2025-03-20",
        "url": "https://example-airline.com/flights?from=SFO&to=ORD&date=2025-03-20",
    },
]

monitor = FareMonitor()
results = monitor.check_fares(routes)
monitor.export_report()

Planlama

# Check fares every 4 hours
0 */4 * * * cd /opt/fare-monitor && python fare_monitor.py

Maliyet Analizi

İzleme Seviyesi Rotalar Çekler/Day CAPTCHA'lar/Day Tahmini Maliyet
Kişisel 5 6/route ~30 0,50$
Küçük Ajans 50 4/route ~200 2-5$
kurumsal 500 6/route ~3.000 20-40$

SSS

Ücretleri ne sıklıkla kontrol etmeliyim?

Kişisel kullanım için her 4-6 saatte bir. İş amaçlı kullanım için her 1-2 saatte bir. Havayolları fiyatları toplu olarak güncelliyor, dolayısıyla daha sık kontroller azalan getiri sağlıyor.

Otel fiyatlarını da takip edebilir miyim?

Evet. Aynı yaklaşım Booking.com, Expedia ve doğrudan otel siteleri için de geçerlidir. Otel sayfası biçimleri için fiyat çıkarma modellerini ayarlayın.

Dinamik fiyatlandırma sayfalarını nasıl yönetirim?

Bazı seyahat siteleri JavaScript oluşturmayı gerektirir. Sayfayı getirmek için Selenium veya Playwright'ı, ardından CAPTCHA çözümü için CaptchaAI'yi kullanın.

İlgili Kılavuzlar

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