Use Cases

Automatisation du portail gouvernemental avec la résolution de CAPTCHA

L'automatisation d'une démarche administrative bute presque toujours sur le même obstacle : un CAPTCHA à l'entrée du formulaire, du rendez-vous ou du registre. CaptchaAI le résout — reCAPTCHA v2, CAPTCHA image/OCR, BLS CAPTCHA — via une seule API, pour que vos tests QA et démarches autorisées aillent jusqu'au bout sans saisie manuelle.

Périmètre sûr. Ce guide vise les équipes QA, la civic tech et les professions juridiques. Restez sur vos propres dossiers et environnements autorisés, et vérifiez vos obligations RGPD.


Quels CAPTCHA sur quels portails publics

Identifiez d'abord le type de défi. Les administrations ont souvent une génération de retard : l'image et le reCAPTCHA v2 dominent, rarement les défis récents.

Catégorie de portail CAPTCHA courant Exemples de sites Cas d'usage
Visas / immigration BLS, reCAPTCHA v2 Portails BLS, USCIS Rendez-vous
Immatriculation reCAPTCHA v2, image Préfectures, DMV Renouvellement
Dossiers judiciaires reCAPTCHA v2 PACER, tribunaux Consultation
Permis / licences CAPTCHA image Portails municipaux Dépôt de demande
Portails fiscaux reCAPTCHA v2 Sites des impôts Suivi
Registres publics CAPTCHA image, reCAPTCHA Registres fonciers Titres de propriété

Prise de rendez-vous sur les portails de visa BLS

Les portails BLS, au cœur du parcours de visa en Afrique du Nord francophone, utilisent leur propre CAPTCHA. CaptchaAI le prend en charge avec un taux de réussite élevé :

import requests
import time
import base64

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"


def solve_bls_captcha(captcha_image_url, session):
    """Solve BLS-specific CAPTCHA."""
    # Download CAPTCHA image
    img_resp = session.get(captcha_image_url)
    img_b64 = base64.b64encode(img_resp.content).decode()

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "base64",
        "body": img_b64,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(30):
        time.sleep(3)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]

    raise TimeoutError("BLS CAPTCHA timeout")


class BLSAppointmentBooker:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
        })

    def login(self, portal_url, email, password):
        """Login to BLS portal with CAPTCHA."""
        resp = self.session.get(portal_url)

        # Extract CAPTCHA image URL from page
        import re
        match = re.search(r'src="(/captcha[^"]+)"', resp.text)
        if match:
            captcha_url = portal_url.rstrip("/") + match.group(1)
            captcha_text = solve_bls_captcha(captcha_url, self.session)
        else:
            captcha_text = ""

        login_resp = self.session.post(portal_url, data={
            "email": email,
            "password": password,
            "captcha": captcha_text,
        })
        return login_resp.status_code == 200

    def check_appointment_slots(self, slots_url):
        """Check available appointment slots."""
        resp = self.session.get(slots_url)
        if resp.status_code == 200:
            return resp.json().get("available_slots", [])
        return []

    def book_slot(self, booking_url, slot_id, applicant_data):
        """Book an appointment slot, handling any CAPTCHA."""
        resp = self.session.get(booking_url)

        # Check for CAPTCHA on booking page
        import re
        match = re.search(r'src="(/captcha[^"]+)"', resp.text)
        if match:
            captcha_url = booking_url.rstrip("/") + match.group(1)
            captcha_text = solve_bls_captcha(captcha_url, self.session)
        else:
            captcha_text = ""

        resp = self.session.post(booking_url, data={
            "slot_id": slot_id,
            "captcha": captcha_text,
            **applicant_data,
        })

        return {
            "success": resp.status_code == 200,
            "confirmation": resp.json().get("confirmation_number"),
        }

La classe télécharge l'image, la résout, puis rejoue la réponse à la connexion et à la réservation. Réservez-la à votre propre dossier : elle fiabilise une démarche légitime, pas la monopolisation de créneaux.


Consultation des dossiers judiciaires (reCAPTCHA v2)

Les greffes et bases de jurisprudence protègent souvent leur recherche par reCAPTCHA v2. Vous soumettez le sitekey, puis replacez le token g-recaptcha-response dans la requête :

def solve_recaptcha(sitekey, pageurl):
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]
    raise TimeoutError("Timeout")


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

    def search_cases(self, court_url, search_params, sitekey):
        """Search court records with reCAPTCHA handling."""
        # Load search page
        self.session.get(court_url)

        # Solve CAPTCHA
        token = solve_recaptcha(sitekey, court_url)

        # Submit search with token
        resp = self.session.post(court_url, data={
            **search_params,
            "g-recaptcha-response": token,
        })

        if resp.status_code == 200:
            return self._parse_results(resp.text)
        return []

    def _parse_results(self, html):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")
        cases = []
        for row in soup.select("table.results tr")[1:]:
            cols = row.select("td")
            if len(cols) >= 4:
                cases.append({
                    "case_number": cols[0].get_text(strip=True),
                    "parties": cols[1].get_text(strip=True),
                    "date": cols[2].get_text(strip=True),
                    "status": cols[3].get_text(strip=True),
                })
        return cases

Un schéma reCAPTCHA v2 réutilisable

Le même schéma — récupérer, injecter, analyser — vaut pour tout portail protégé par reCAPTCHA v2.


CAPTCHA image sur les portails de permis municipaux

De nombreux portails de communes utilisent de simples CAPTCHA image, résolus par OCR depuis l'image en base64 :

def solve_image_captcha(image_url, session):
    """Solve image-based CAPTCHA common on local government sites."""
    img = session.get(image_url)
    img_b64 = base64.b64encode(img.content).decode()

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "base64",
        "body": img_b64,
        "json": 1,
    })
    task_id = resp.json()["request"]

    for _ in range(20):
        time.sleep(3)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]

    raise TimeoutError("Image CAPTCHA timeout")

Recherche en lot dans les registres publics

Pour croiser plusieurs adresses dans un registre foncier, résolvez le CAPTCHA une fois par lot, en espaçant les appels :

import csv


def batch_property_lookup(addresses, portal_url, sitekey, output_file):
    """Look up multiple property records, solving CAPTCHA per batch."""
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
    })

    results = []
    for i, address in enumerate(addresses):
        try:
            # Solve CAPTCHA every 5th request (or when required)
            if i % 5 == 0:
                token = solve_recaptcha(sitekey, portal_url)

            resp = session.post(portal_url, data={
                "address": address,
                "g-recaptcha-response": token,
            })

            if resp.status_code == 200:
                results.append({
                    "address": address,
                    "data": resp.json(),
                })

            time.sleep(3)  # Be respectful

        except Exception as e:
            results.append({"address": address, "error": str(e)})

    # Save results
    with open(output_file, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["address", "data", "error"])
        writer.writeheader()
        writer.writerows(results)

    return results

Réflexe RGPD. Sur des données personnelles, n'extrayez que le strict nécessaire et gardez une trace de votre base légale.


Gérer les délais de session courts

Les portails gouvernementaux expirent vite. Adaptez le rythme au délai constaté et gardez la même IP (proxy collant) sur un formulaire multi-pages :

Type de portail Expiration de session Recommandation
Portails de visa 5–10 min Terminez le flux rapidement
Sites d'immatriculation 15 min Rafraîchissez le cookie à mi-parcours
Dossiers judiciaires 20–30 min Groupez les recherches par lots
Portails fiscaux 10–15 min Proxy collant, même IP
Portails de permis 30 min Sauvegardez à chaque étape

Dépannage

Problème Cause Correctif
L'image du CAPTCHA ne se charge pas Cookie de session expiré Ouvrez une nouvelle session
« Session expirée » pendant le formulaire Résolution trop lente Résolvez juste avant l'envoi
Réponse CAPTCHA erronée Image déformée Signalez l'image via l'API
Le portail bloque l'automatisation Détection IP/UA Proxy résidentiel + User-Agent réel
Erreur de validation après le CAPTCHA Token expiré côté serveur Résolvez et soumettez dans la foulée

FAQ

L'automatisation d'un portail public est-elle autorisée ?

Oui, pour vos propres formulaires et la consultation de données publiques ; les tests QA de civic tech sont un usage légitime. Vérifiez les conditions du portail et le RGPD.

CaptchaAI prend-il en charge les BLS CAPTCHA ?

Oui. Utilisez method=bls en direct ou method=base64 pour l'image ; le taux de réussite est élevé. Le guide du solveur BLS détaille le paramétrage.

Quel plan CaptchaAI convient à des démarches ponctuelles ?

Pour un volume faible et non parallèle, l'offre BASIC ($15/mois, 5 threads) suffit : chaque thread traite un CAPTCHA à la fois, sans limite mensuelle de résolutions. Montez en gamme pour du parallèle.

Faut-il un proxy résidentiel pour ces portails ?

Souvent : les administrations filtrent les IP datacenter et vérifient la cohérence IP/User-Agent. Un proxy résidentiel à IP collante et un User-Agent réel réduisent les blocages.

Comment fiabiliser un rendez-vous qui expire trop vite ?

Résolvez le CAPTCHA au dernier moment, gardez la session et la même IP, et sauvegardez la progression pour reprendre sans tout refaire.


Pour aller plus loin



Étapes suivantes

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