Use Cases

Surveillance des tickets d'événement avec gestion CAPTCHA

Un moniteur de billetterie ne sert à rien s'il se fait bloquer au premier défi CAPTCHA. Dès que vous interrogez régulièrement une page d'événement — concert, match, festival —, la plateforme sert un reCAPTCHA v2, un Cloudflare Turnstile ou une page Cloudflare Challenge. CaptchaAI résout ce défi à la volée : votre script récupère un token valide, le renvoie avec sa requête et lit la disponibilité.

Ce guide construit un moniteur en Python qui détecte le CAPTCHA, le résout via l'API et vous alerte quand l'état d'un événement change. Le tout dans un périmètre sûr : ciblez vos propres environnements de test ou de préproduction (staging), pas la mise en vente réelle d'un tiers.


Les défis que vous allez rencontrer

Sur les plateformes de billetterie, trois protections reviennent le plus souvent :

  • reCAPTCHA v2 — la case « Je ne suis pas un robot », parfois suivie d'une grille d'images.
  • Cloudflare Turnstile — un défi léger et sans interaction, très répandu.
  • Cloudflare Challenge — la page interstitielle « Vérification de votre navigateur ».

CaptchaAI prend en charge ces trois types ; hCaptcha et FunCaptcha, en revanche, ne sont pas encore couverts.


Comment fonctionne la surveillance

La boucle enchaîne quatre étapes :

  1. interroger la page de chaque événement ;
  2. résoudre le CAPTCHA s'il apparaît ;
  3. comparer la disponibilité à la dernière valeur connue ;
  4. envoyer une alerte en cas de changement.
Configure events → Check availability → CAPTCHA?
                                           ↓ Yes
                                      Solve via CaptchaAI → Retry
                                           ↓ No
                                      Parse availability → Changed?
                                                             ↓ Yes
                                                         Send alert

Ce qu'il vous faut avant de commencer

Exigence Détails
Clé API CaptchaAI captchaai.com
Python 3.8+ Avec requests
Proxy Proxy résidentiel recommandé
pip install requests

Le proxy résidentiel n'est pas un détail : les sites de billetterie bloquent en priorité les IP de datacenter. Prévoyez également :

  • une rotation de proxys pour répartir les requêtes sur plusieurs IP ;
  • une persistance de session (cookies) pour ne pas repartir de zéro à chaque passage ;
  • un canal d'alerte (e-mail, webhook Slack) pour être prévenu d'un changement d'état.

La fonction de résolution CAPTCHA

Soumettre le défi puis interroger le résultat

Cette fonction générique envoie le défi à l'API, patiente, puis interroge le résultat jusqu'à obtenir le token. L'attente initiale est plus courte pour Turnstile (10 s) que pour reCAPTCHA (20 s).

import requests
import time

API_KEY = "YOUR_API_KEY"


def solve_captcha(method, params):
    """Generic CaptchaAI solver for any supported method."""
    params["key"] = API_KEY
    params["json"] = 1

    submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()

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

    task_id = submit["request"]
    initial_wait = 10 if method == "turnstile" else 20
    time.sleep(initial_wait)

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

Le moniteur de billetterie

Détecter le défi et lire la disponibilité

La classe TicketMonitor conserve une session, détecte le type de défi et renvoie le token dans le champ attendu — g-recaptcha-response pour reCAPTCHA, cf-turnstile-response pour Turnstile. Elle mémorise le dernier état de chaque événement pour n'alerter que sur un vrai changement.

from datetime import datetime
import json


class TicketMonitor:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        if proxy:
            self.session.proxies = {
                "http": f"http://{proxy}",
                "https": f"http://{proxy}"
            }
        self.last_status = {}

    def check_event(self, event):
        """Check ticket availability for an event, solving CAPTCHAs if needed."""
        url = event["url"]
        response = self.session.get(url)

        # Handle CAPTCHA if detected
        if "g-recaptcha" in response.text or "recaptcha" in response.text:
            sitekey = self._extract_sitekey(response.text)
            if sitekey:
                token = solve_captcha("userrecaptcha", {
                    "method": "userrecaptcha",
                    "googlekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "g-recaptcha-response": token
                })

        elif "cf-turnstile" in response.text:
            sitekey = self._extract_turnstile_key(response.text)
            if sitekey:
                token = solve_captcha("turnstile", {
                    "method": "turnstile",
                    "sitekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "cf-turnstile-response": token
                })

        # Parse availability
        availability = self._parse_availability(response.text, event)

        # Check for changes
        event_key = event["name"]
        if event_key in self.last_status:
            if availability != self.last_status[event_key]:
                self._send_alert(event, availability)

        self.last_status[event_key] = availability
        return availability

    def _extract_sitekey(self, html):
        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:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _parse_availability(self, html, event):
        """Parse ticket availability. Customize per ticketing site."""
        available = "sold out" not in html.lower()
        return {
            "event": event["name"],
            "available": available,
            "checked_at": datetime.now().isoformat()
        }

    def _send_alert(self, event, availability):
        """Send availability change notification."""
        status = "AVAILABLE" if availability["available"] else "SOLD OUT"
        print(f"[ALERT] {event['name']}: {status}")

    def monitor_all(self, events):
        """Check all events and return results."""
        results = []
        for event in events:
            try:
                result = self.check_event(event)
                results.append(result)
                print(f"[OK] {event['name']}: {'available' if result['available'] else 'sold out'}")
            except Exception as e:
                print(f"[ERROR] {event['name']}: {e}")
        return results


# Usage
events = [
    {
        "name": "Concert - Madison Square Garden - Aug 15",
        "url": "https://example-tickets.com/event/12345"
    },
    {
        "name": "Basketball Finals - Game 7",
        "url": "https://example-tickets.com/event/67890"
    }
]

monitor = TicketMonitor(proxy="user:pass@proxy.example.com:8080")
results = monitor.monitor_all(events)

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

Résultat attendu :

[OK] Concert - Madison Square Garden - Aug 15: available
[OK] Basketball Finals - Game 7: sold out

La méthode _parse_availability est volontairement simple : adaptez-la au HTML réel de chaque plateforme.


Planifier les vérifications

Lancez le moniteur à intervalle régulier avec cron plutôt qu'en boucle infinie : un échec ponctuel n'arrête alors pas la surveillance.

# Check every 15 minutes
*/15 * * * * cd /path/to/project && python ticket_monitor.py >> /var/log/tickets.log 2>&1

Un worker OVHcloud ou Scaleway proche de vos cibles garde la latence basse. Espacez les vérifications pour rester sous les seuils de débit.


Bonnes pratiques de surveillance

Quelques réflexes évitent la plupart des blocages :

  • Espacez les vérifications : 10 à 30 minutes suffisent pour la plupart des événements ; réservez les intervalles courts aux mises en vente réellement tendues.
  • Isolez les erreurs : une exception sur un événement ne doit pas interrompre les autres, comme le fait déjà monitor_all.
  • Journalisez chaque passage : un historique daté aide à repérer une IP grillée ou un changement de structure de page.

Dépannage

Problème Cause Correctif
Un CAPTCHA à chaque vérification Même IP, session non persistée Conservez les cookies et alternez des proxys résidentiels
Blocage après quelques passages Limitation de débit atteinte Allongez l'intervalle et activez la rotation de proxys
État de disponibilité erroné La structure de la page a changé Adaptez la méthode _parse_availability
Résolution CAPTCHA lente Forte charge côté solveur Ajoutez une nouvelle tentative avec backoff exponentiel

FAQ

Combien de threads pour surveiller plusieurs événements en parallèle ?

Un thread traite un CAPTCHA à la fois. Un moniteur séquentiel se contente d'un thread ; pour du simultané, comptez un thread par résolution concurrente. Le plan BASIC ($15/mois, 5 threads) couvre déjà une poignée d'événements en parallèle.

CaptchaAI prend-il en charge hCaptcha sur les sites de billetterie ?

Non — hCaptcha n'est pas encore pris en charge, tout comme FunCaptcha. Concentrez votre moniteur sur reCAPTCHA v2, Cloudflare Turnstile et Cloudflare Challenge, qui couvrent la majorité des défis rencontrés.

Comment réduire la fréquence des CAPTCHA ?

Persistez la session, réutilisez les cookies et faites tourner des proxys résidentiels. Un rythme raisonnable (toutes les 10 à 30 minutes) déclenche nettement moins de défis qu'une salve de requêtes depuis un datacenter.

Que faire face aux files d'attente virtuelles ?

Les salles d'attente sont distinctes du CAPTCHA. Votre moniteur doit repérer la page de file d'attente, patienter puis réessayer. CaptchaAI résout le défi qui apparaît une fois la file franchie, pas la file elle-même.

Est-ce conforme de surveiller la disponibilité des billets ?

Restez sur vos propres environnements de test, respectez les conditions d'utilisation du site ciblé et minimisez les données personnelles collectées, conformément au RGPD. Ce guide vise la validation de parcours en staging.


Créez votre compte CaptchaAI

Démarrez la surveillance de la disponibilité sur captchaai.com et laissez l'API gérer les défis reCAPTCHA v2 et Turnstile au fil de vos vérifications.


Guides associés

Les commentaires sont désactivés pour cet article.