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.