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
- Comparación de Geetest y Cloudflare Turnstile
- Cloudflare Turnstile 403 Después de la corrección del token
- Modos de widget Cloudflare Turnstile explicados
Próximos pasos
Cree un seguimiento de vuelos fiable:obtenga su clave API CaptchaAIy manejar CAPTCHA de aerolíneas automáticamente.