Casos de Uso

Manejo de CAPTCHA para monitorear el estado del vuelo

El monitoreo del estado de los vuelos requiere controles frecuentes en múltiples portales de aerolíneas y aeropuertos. Estos portales protegen sus datos en tiempo real con Cloudflare Turnstile, reCAPTCHA y CAPTCHA personalizados, especialmente cuando detectan consultas automatizadas repetidas. A continuación se explica cómo manejar los CAPTCHA mientras se crean herramientas confiables de seguimiento de vuelos.

Dónde aparecen los CAPTCHA

Tipo de portal CAPTCHA gatillo
Página de estado de vuelo de aerolínea Cloudflare Turnstile Solicitudes frecuentes desde la misma IP
Llegada al aeropuerto/departure tableros Cloudflare Challenge Detección de robots
Motores de búsqueda de vuelos reCAPTCHA v2/v3 Envío del formulario de búsqueda
Comprobación del estado de la reserva reCAPTCHA v2 Antes de mostrar itinerario
Páginas de límite de velocidad API CAPTCHA personalizado Después de exceder los límites de solicitud

Arquitectura de monitoreo de vuelo

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

Monitoreo periódico con manejo de 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")

Monitoreo de múltiples aerolíneas (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());
  }
}

Frecuencia de monitoreo y tasas de CAPTCHA

Verificar frecuencia Tasa CAPTCHA típica Recomendación
Cada 1 minuto Alto (50-80%) Demasiado agresivo: aumente el intervalo
Cada 5 minutos Moderado (10-30%) Aceptable para vuelos críticos
Cada 15 minutos Bajo (5-10%) Buen equilibrio para el seguimiento de rutina
Cada 30 minutos Muy bajo (<5%) Lo mejor para el seguimiento a largo plazo
cada hora Mínimo (<1%) Los CAPTCHA rara vez se activan

Optimización de sesión

Reduzca los encuentros con CAPTCHA manteniendo el estado de la sesión:

Técnica Efecto
Persistir cookies entre comprobaciones Cloudflare qa_validation_cookie válido por 15 a 30 minutos
Utilice un agente de usuario coherente Cambiar la UA desencadena nuevos desafíos
Mantener la coherencia del proxy La misma IP reduce las sospechas
Solicitudes de espacio de manera uniforme Los patrones de ráfaga activan límites de tasa

Solución de problemas

Problema causa Solución
CAPTCHA cada cheque La sesión no persistió Reutilizar requests.Session() en todos los cheques
Bloqueo de Cloudflare (Error 1020) Demasiadas solicitudes Aumentar el intervalo de control
Datos de vuelo desactualizados después de CAPTCHA El token expiró durante la resolución Utilice la resolución justo a tiempo
Datos diferentes a los que muestra el navegador Falta representación de JavaScript Utilice la automatización del navegador para sitios con mucho JS

Preguntas frecuentes

¿Con qué frecuencia debo verificar el estado del vuelo?

Lo normal es cada 5 a 15 minutos. Las comprobaciones más frecuentes activan más CAPTCHA y pueden provocar bloqueos de IP. CaptchaAI maneja Turnstile con una tasa de éxito del 100%, por lo que el factor limitante son los límites de velocidad del portal, no la resolución de CAPTCHA.

¿Puedo monitorear vuelos de varias aerolíneas a la vez?

Sí. Utilice sesiones separadas por aerolínea y resuelva los CAPTCHA de forma independiente para cada una. CaptchaAI maneja solicitudes simultáneas en diferentes sitios.

¿Las API móviles de las aerolíneas tienen CAPTCHA?

Las API móviles suelen utilizar una autenticación diferente (claves API, OAuth) en lugar de CAPTCHA. Sin embargo, es posible que los puntos finales web a los que sirven aún tengan protección de Cloudflare.

Artículos relacionados

Próximos pasos

Cree un seguimiento de vuelos fiable:obtenga su clave API CaptchaAIy manejar CAPTCHA de aerolíneas automáticamente.

Los comentarios están deshabilitados para este artículo.