حالات الاستخدام

التعامل مع اختبار CAPTCHA لمراقبة حالة الرحلة

تتطلب مراقبة حالة الرحلة إجراء فحوصات متكررة عبر العديد من بوابات شركات الطيران والمطارات. تحمي هذه البوابات بياناتها في الوقت الفعلي باستخدام Cloudflare Turnstile وreCAPTCHA واختبارات CAPTCHA المخصصة - خاصة عندما تكتشف الاستعلامات الآلية المتكررة. وإليك كيفية التعامل مع اختبارات CAPTCHA أثناء إنشاء أدوات موثوقة لتتبع الرحلات الجوية.

مكان ظهور اختبار CAPTCHA

نوع البوابة اختبار CAPTCHA المحفّز
صفحة حالة رحلة طيران Cloudflare Turnstile طلبات متكررة من نفس IP
الوصول إلى المطار لوحات /departure Cloudflare Challenge كشف البوت
محركات بحث الطيران reCAPTCHA v2/v3 تقديم نموذج البحث
التحقق من حالة الحجز reCAPTCHA v2 قبل عرض خط سير الرحلة
صفحات الحد الأقصى لمعدل API اختبار CAPTCHA المخصص بعد تجاوز حدود الطلب

هندسة مراقبة الطيران

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()
        }

المراقبة الدورية من خلال التعامل مع اختبار CAPTCHA

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")

مراقبة شركات الطيران المتعددة (JavaScript)

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());
  }
}

مراقبة الترددات ومعدلات CAPTCHA

تحقق من التردد معدل CAPTCHA النموذجي توصية
كل 1 دقيقة عالية (50-80%) عدوانية للغاية - قم بزيادة الفاصل الزمني
كل 5 دقائق معتدل (10-30%) مقبول للرحلات الحرجة
كل 15 دقيقة منخفض (5-10%) توازن جيد للمراقبة الروتينية
كل 30 دقيقة منخفضة جدًا (<5%) الأفضل للتتبع على المدى الطويل
كل ساعة الحد الأدنى (<1%) نادرًا ما يتم تفعيل اختبارات CAPTCHA

تحسين الجلسة

تقليل مواجهات اختبار CAPTCHA من خلال الحفاظ على حالة الجلسة:

تقنية تأثير
ملفات تعريف الارتباط المستمرة بين الشيكات Cloudflare cf_clearance صالحة لمدة 15-30 دقيقة
استخدم وكيل مستخدم متسقًا يؤدي تغيير تعميم الوصول إلى الخدمات إلى ظهور تحديات جديدة
الحفاظ على اتساق الوكيل نفس IP يقلل من الشك
طلبات الفضاء بالتساوي أنماط الانفجار تؤدي إلى حدود للمعدل

استكشاف الأخطاء وإصلاحها

المشكلة السبب الإجراء
تظهر اختبارات CAPTCHA كثيرة خلال فترة قصيرة إيقاع الجمع أو مستوى التوازي أعلى من اللازم بالنسبة للمصدر خفّض التكرار وحافظ على استقرار الجلسات وراجع جودة الوكيل
البيانات ناقصة حتى بعد حل CAPTCHA أداة الاستخراج تقرأ عرضًا قديمًا أو غير مكتمل استخرج البيانات بعد تطبيق الرمز المميز داخل الجلسة نفسها
ترتفع التكلفة أسرع من المتوقع تؤدي كثرة إعادة المحاولات أو الصفحات غير الضرورية إلى تحديات إضافية اقصر الحل على الخطوات الحرجة وتتبع إعادة المحاولات لكل مصدر

الخطوات التالية

أدلة ذات صلة

التعليقات غير مفعّلة لهذا المقال.