La surveillance du statut des vols nécessite des contrôles fréquents sur plusieurs portails de compagnies aériennes et d'aéroports. Ces portails protègent leurs données en temps réel avec Cloudflare Turnstile, reCAPTCHA et CAPTCHA personnalisés - en particulier lorsqu'ils détectent des requêtes automatisées répétées. Voici comment gérer les CAPTCHA tout en créant des outils de suivi de vol fiables.
Où apparaissent les CAPTCHA
| Type de portail | CAPTCHA | Déclencheur |
|---|---|---|
| Page d'état des vols de la compagnie aérienne | Cloudflare Turnstile | Requêtes fréquentes depuis la même adresse IP |
| Arrivée à l'aéroportTableaux /departure | Cloudflare Challenge | Détection de robots |
| Moteurs de recherche de vols | reCAPTCHA v2/v3 | Envoi du formulaire de recherche |
| Vérification du statut de la réservation | reCAPTCHA v2 | Avant d'afficher l'itinéraire |
| Pages de limite de débit de l'API | CAPTCHA personnalisé | Après avoir dépassé les limites de requêtes |
Architecture de surveillance des vols
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_of(node):
return node.get_text(strip=True) if node else None
return {
"status": text_of(soup.select_one(".flight-status")),
"departure": text_of(soup.select_one(".departure-time")),
"arrival": text_of(soup.select_one(".arrival-time")),
"gate": text_of(soup.select_one(".gate-info")),
"checked_at": datetime.now().isoformat(),
}
Surveillance périodique avec gestion 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")
Surveillance multi-compagnies aériennes (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());
}
}
Fréquence de surveillance et taux de CAPTCHA
| Vérifier la fréquence | Taux CAPTCHA typique | Recommandation |
|---|---|---|
| Toutes les 1 minutes | Élevé (50 à 80 %) | Trop agressif – augmenter l'intervalle |
| Toutes les 5 minutes | Modéré (10 à 30 %) | Acceptable pour les vols critiques |
| Toutes les 15 minutes | Faible (5 à 10 %) | Bon équilibre pour une surveillance de routine |
| Toutes les 30 minutes | Très faible (<5%) | Idéal pour le suivi à long terme |
| Toutes les heures | Minime (<1%) | Les CAPTCHA se déclenchent rarement |
Optimisation des sessions
Réduisez les rencontres CAPTCHA en conservant l’état de la session :
| Technique | Effet |
|---|---|
| Conserver les cookies entre les vérifications | Cloudflare cf_clearance valable 15 à 30 minutes |
| Utiliser un agent utilisateur cohérent | Changer l’AU soulève de nouveaux défis |
| Maintenir la cohérence des proxys | La même adresse IP réduit les soupçons |
| Espacer les demandes de manière uniforme | Les modèles de rafales déclenchent des limites de débit |
Dépannage
| Problème | Parce que | Corriger |
|---|---|---|
| CAPTCHA à chaque chèque | Session non persistante | Réutiliser requests.Session() entre les chèques |
| Bloc Cloudflare (Erreur 1020) | Trop de demandes | Augmenter l'intervalle de contrôle |
| Données de vol obsolètes après CAPTCHA | Le jeton a expiré pendant la résolution | Utiliser la résolution juste à temps |
| Données différentes de celles affichées par le navigateur | Rendu JavaScript manquant | Utiliser l'automatisation du navigateur pour les sites utilisant beaucoup de JS |
FAQ
À quelle fréquence dois-je vérifier le statut du vol ?
Toutes les 5 à 15 minutes sont typiques. Des contrôles plus fréquents déclenchent davantage de CAPTCHA et peuvent entraîner des blocages IP. CaptchaAI gère Turnstile avec un taux de réussite de 100 %, le facteur limitant est donc les limites de débit du portail, et non la résolution de CAPTCHA.
Puis-je surveiller les vols de plusieurs compagnies aériennes à la fois ?
Oui. Utilisez des sessions distinctes par compagnie aérienne et résolvez les CAPTCHA indépendamment pour chacune. CaptchaAI gère les demandes simultanées sur différents sites.
Les API mobiles des compagnies aériennes comportent-elles des CAPTCHA ?
Les API mobiles utilisent généralement une authentification différente (clés API, OAuth) plutôt que des CAPTCHA. Cependant, les points de terminaison Web qu’ils servent peuvent toujours bénéficier d’une protection Cloudflare.
Articles connexes
- Comparaison Geetest et Cloudflare Turnstile
- Cloudflare Turnstile 403 après la correction du jeton
- Modes du widget Cloudflare Turnstile expliqués
Prochaines étapes
Construisez une surveillance des vols fiable -récupérez votre clé API CaptchaAIet gérez automatiquement les CAPTCHA des compagnies aériennes.