Casos de Uso

Monitoreo de tarifas aéreas con manejo CAPTCHA

Los sitios de viajes y aerolíneas utilizan con frecuencia CAPTCHA para limitar la verificación automática de tarifas. Un sistema de seguimiento de precios que verifique las tarifas en múltiples rutas enfrentará desafíos reCAPTCHA, anuncios intersticiales de Cloudflare y mecanismos de limitación de tarifas. CaptchaAI maneja el paso de resolución de CAPTCHA para que su canal de monitoreo pueda continuar recopilando datos de tarifas.

Esta guía muestra cómo crear un flujo de trabajo de monitoreo de tarifas que detecte y resuelva CAPTCHA durante las verificaciones de precios.


El flujo de trabajo de monitoreo

Schedule check → Request fare page → CAPTCHA detected?
                                         ↓ Yes
                                    Solve via CaptchaAI → Inject token → Retry request
                                         ↓ No
                                    Parse fare data → Store → Alert on price change

Lo que necesitas

Requisito Detalles
API key de CaptchaAI captchaai.com
Python 3.8+ Con requests
Proxy Red residencial autorizada para sitios de viajes
pip install requests

Ayudante del solucionador CaptchaAI

import requests
import time

API_KEY = "YOUR_API_KEY"


def solve_recaptcha_v2(sitekey, pageurl):
    """Solve reCAPTCHA v2 and return the token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY, "method": "userrecaptcha",
        "googlekey": sitekey, "pageurl": pageurl, "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    time.sleep(20)

    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")


def solve_turnstile(sitekey, pageurl):
    """Solve Cloudflare Turnstile and return the token."""
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY, "method": "turnstile",
        "sitekey": sitekey, "pageurl": pageurl, "json": 1
    }).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    time.sleep(10)

    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")

Monitoreo de tarifas con manejo CAPTCHA

import json
from datetime import datetime


class FareMonitor:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {
                "http": f"http://{proxy}",
                "https": f"http://{proxy}"
            }
        self.fare_history = {}

    def check_fare(self, route):
        """Check fare for a route, solving CAPTCHAs if needed."""
        url = route["url"]

        response = self.session.get(url)

        # Detect CAPTCHA in response
        if self._has_recaptcha(response.text):
            sitekey = self._extract_sitekey(response.text)
            token = solve_recaptcha_v2(sitekey, url)
            response = self.session.post(url, data={
                "g-recaptcha-response": token,
                **route.get("params", {})
            })

        elif self._has_turnstile(response.text):
            sitekey = self._extract_turnstile_key(response.text)
            token = solve_turnstile(sitekey, url)
            response = self.session.post(url, data={
                "cf-turnstile-response": token,
                **route.get("params", {})
            })

        return self._parse_fare(response.text, route)

    def _has_recaptcha(self, html):
        return "g-recaptcha" in html or "recaptcha/api" in html

    def _has_turnstile(self, html):
        return "cf-turnstile" in html or "turnstile" in html

    def _extract_sitekey(self, html):
        # Extract data-sitekey from reCAPTCHA div
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _extract_turnstile_key(self, html):
        if 'data-sitekey="' in html:
            idx = html.index("cf-turnstile")
            start = html.index('data-sitekey="', idx) + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _parse_fare(self, html, route):
        """Parse fare data from common airline result layouts."""
        from bs4 import BeautifulSoup
        import re

        soup = BeautifulSoup(html, "html.parser")
        selectors = [
            "[data-testid='price-value']",
            ".fare-amount",
            ".price-total",
            ".booking-price",
        ]

        price_text = ""
        for selector in selectors:
            el = soup.select_one(selector)
            if el and el.get_text(strip=True):
                price_text = el.get_text(strip=True)
                break

        amount_match = re.search(r"(\d[\d,\.]+)", price_text or html)
        currency_match = re.search(r"(USD|EUR|GBP|\$|€|£)", price_text or html)

        return {
            "route": route["name"],
            "carrier": route.get("carrier", "unknown"),
            "price_text": price_text or None,
            "amount": amount_match.group(1) if amount_match else None,
            "currency": currency_match.group(1) if currency_match else route.get("currency"),
            "captured_at": datetime.now().isoformat(),
            "source_url": route["url"],
        }

    def monitor_routes(self, routes):
        """Check all routes and report price changes."""
        results = []
        for route in routes:
            try:
                fare = self.check_fare(route)
                results.append(fare)
                print(f"[OK] {route['name']}: checked")
            except Exception as e:
                print(f"[ERROR] {route['name']}: {e}")
        return results


# Usage
routes = [
    {
        "name": "NYC-LAX",
        "url": "https://example-airline.com/search?from=JFK&to=LAX&date=2025-08-15",
        "params": {"adults": 1}
    },
    {
        "name": "SFO-ORD",
        "url": "https://example-airline.com/search?from=SFO&to=ORD&date=2025-08-20",
        "params": {"adults": 1}
    }
]

monitor = FareMonitor(proxy="user:pass@proxy.example.com:8080")
results = monitor.monitor_routes(routes)

for r in results:
    print(json.dumps(r, indent=2))

Verificaciones de programación

Ejecute el monitor según una programación utilizando cron o un programador de tareas:

# Check fares every 6 hours
0 */6 * * * cd /path/to/project && python fare_monitor.py >> /var/log/fares.log 2>&1

Solución de problemas

Problema causa Solución
CAPTCHA frecuentes Demasiadas solicitudes de la misma IP Utilice proxies residenciales rotativos
Precios obsoletos Páginas almacenadas en caché Agregue encabezados anti-caché o aleatorice los parámetros de solicitud
IP bloqueada Limitación de velocidad Aumentar los retrasos entre controles, rotar proxies
La resolución de CAPTCHA falla Extracción de clave de sitio incorrecta Verifique que la clave del sitio coincida con el CAPTCHA de la página

Preguntas frecuentes

¿Con qué frecuencia debo consultar las tarifas?

Lo normal es cada 4 a 8 horas. Las comprobaciones más frecuentes aumentan los encuentros con CAPTCHA y los costos de proxy.

¿Qué tipos de CAPTCHA utilizan los sitios de las aerolíneas?

Más comúnmente, reCAPTCHA v2, Cloudflare Turnstile o páginas de desafío y, ocasionalmente, CAPTCHA de imágenes.

¿Necesito proxies residenciales?

Sí. Los sitios de viajes bloquean activamente las direcciones IP de los centros de datos. Los proxies residenciales o móviles tienen tasas de éxito significativamente más altas.

¿Puedo monitorear varias aerolíneas?

Sí. Personalice el método _parse_fare para el formato de respuesta de cada aerolínea y agregue rutas para cada sitio.

¿Cómo manejo las páginas Cloudflare Challenge?

Utilice method=cloudflare_challenge con un proxy. La cookie qa_validation_cookie devuelta otorga acceso al sitio. Ver la guía de Cloudflare Challenge.


Obtenga su clave API CaptchaAI

Comienza a monitorear las tarifas aéreas en captchaai.com. Maneja CAPTCHA automáticamente en tu flujo de trabajo de seguimiento de precios.


Guías relacionadas

  • Cómo resolver reCAPTCHA v2 usando API
  • Cómo resolver Cloudflare Turnstile usando API
  • Extracción de datos financieros con manejo de CAPTCHA
  • Monitoreo de viajes
Los comentarios están deshabilitados para este artículo.