Anwendungsfälle

Automatisierung von Regierungsportalen mit CAPTCHA-Lösung

Behördenportale lassen sich automatisiert testen und abfragen – der Engpass ist fast immer das CAPTCHA vor dem Login oder dem Absende-Button. Übergeben Sie genau diese Abfrage an CaptchaAI, läuft der Rest Ihres Workflows unverändert weiter: Formular ausfüllen, Termin prüfen, Datensatz abrufen. Dieser Leitfaden zeigt QA-Teams, Civic-Tech-Entwicklern und Kanzleien, wie sie reCAPTCHA v2, BLS- und Bild-CAPTCHAs auf Visa-, Gerichts- und Registerportalen in Python verarbeiten – mit sauberem Session-Handling und ohne den Ablauf umzubauen.

Der Ansatz ist bewusst schlank: Sie treiben den Browser- oder HTTP-Workflow wie gewohnt, und immer dann, wenn eine Abfrage auftaucht, holen Sie das Token oder den Text von der API und schreiben ihn ins Formularfeld. Kein Bruch in der Ablauflogik, kein manuelles Eingreifen.


Welche CAPTCHAs Behördenportale einsetzen

Behörden hinken bei der CAPTCHA-Technik oft hinterher – in der Praxis begegnen Ihnen daher vor allem reCAPTCHA v2, klassische Bild-CAPTCHAs und, im Visa-Kontext, das eigene System von BLS. Die folgende Übersicht ordnet die häufigsten Portalkategorien ihren typischen Abfragen zu:

Portalkategorie Typisches CAPTCHA Beispiel-Portale Anwendungsfall
Visum / Einwanderung BLS, reCAPTCHA v2 BLS-Portale, USCIS Terminbuchung
Kfz-Zulassung (DMV) reCAPTCHA v2, Bild Zulassungsstellen Zulassung verlängern
Gerichtsakten reCAPTCHA v2 PACER, Landesgerichte Fallrecherche
Genehmigungen / Lizenzen Bild-CAPTCHA Genehmigungsportale Antrag einreichen
Steuerportale reCAPTCHA v2 Finanzämter, Steuerportale Bearbeitungsstatus prüfen
Öffentliche Register Bild-CAPTCHA, reCAPTCHA Grundbuch-, Melderegister Eigentums-/Grundbuchsuche

Für die DACH-Region sind vor allem zwei Kategorien relevant: BLS-Visa-Portale, die viele Antragstellende regelmäßig auf Termine abklopfen, und öffentliche Register für Immobilien- und Firmendaten. Beide sind hier ausführlicher behandelt.


BLS-Portale: Visa-Termine automatisiert prüfen

BLS-Portale bringen ein eigenes CAPTCHA-System mit, das nicht auf reCAPTCHA aufsetzt. CaptchaAI löst BLS-CAPTCHAs mit hoher Erfolgsquote über die Bild-Route: Sie laden das CAPTCHA-Bild aus der Portalseite, schicken es als Base64 an in.php und fragen anschließend das Ergebnis von res.php ab. Der zurückgegebene Text geht als captcha-Feld in Login- und Buchungsformular.

Die folgende Klasse kapselt Login, Slot-Prüfung und Buchung – jeweils mit CAPTCHA-Handling an der Stelle, an der das Portal eine Abfrage einblendet:

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

Wichtig ist die Reihenfolge: Erst kurz vor dem Absenden lösen. BLS-Sessions laufen schnell ab, und ein Token, das Sie zu früh holen, ist beim Abschicken womöglich schon wertlos.


Gerichtsakten mit reCAPTCHA v2 abfragen

Gerichtsportale setzen meist auf reCAPTCHA v2. Hier arbeiten Sie nicht mit einem Bild, sondern mit sitekey und pageurl: CaptchaAI liefert ein g-recaptcha-response-Token zurück, das Sie zusammen mit den Suchparametern absenden. Die CourtRecordSearcher-Klasse kapselt genau diesen Ablauf und parst die Trefferliste anschließend mit BeautifulSoup:

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

Der optionale proxy-Parameter ist kein Detail: Viele Portale prüfen, ob Suchseite und Absenden von derselben IP kommen. Ein Residential-Proxy mit fester IP über die gesamte Session hält diese Konsistenz.


Bild-CAPTCHAs auf Genehmigungsportalen

Viele Stadt- und Kreisportale setzen weiterhin einfache Bild-CAPTCHAs ein – Ziffern- und Buchstabenfolgen ohne Interaktion. Diese laufen über denselben OCR-Weg wie die BLS-Bilder: herunterladen, als Base64 übermitteln, Ergebnis abfragen.

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

Öffentliche Register im Batch abfragen

Für Serienabfragen – etwa Eigentums- oder Grundbuchdaten zu vielen Adressen – lohnt es sich, das CAPTCHA nicht bei jeder einzelnen Anfrage zu lösen, sondern in Intervallen. Die folgende Funktion löst nur jede fünfte Anfrage neu und schreibt die Ergebnisse als CSV weg:

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

Ein DACH-Hinweis dazu: Beim Abruf öffentlicher Register in Serie fallen IP-Adressen und personenbezogene Datensätze unter die DSGVO. Klären Sie vor einem Batch-Lauf Ihre Rechtsgrundlage und die Nutzungsbedingungen des Portals – die Automatisierung ersetzt diese Prüfung nicht. Das time.sleep(3) zwischen den Anfragen ist außerdem kein Beiwerk, sondern gehört zum respektvollen Umgang mit einem öffentlichen Dienst.


Sitzungen sauber verwalten

Behördenportale arbeiten oft mit kurzen Session-Timeouts. Wer den Ablauf zu träge gestaltet, verliert das Token oder gleich die ganze Sitzung. Die folgenden Richtwerte helfen bei der Auslegung:

Portaltyp Session-Timeout Empfehlung
Visa-Portale 5–10 Min Ablauf zügig abschließen
Kfz-Zulassung 15 Min Session-Cookie auf halbem Weg erneuern
Gerichtsakten 20–30 Min Batch-Suchen in Gruppen bündeln
Steuerportale 10–15 Min Sticky-Proxy mit fester IP nutzen
Genehmigungs-Apps 30 Min Fortschritt bei jedem Schritt speichern

Typische Probleme und Lösungen

Problem Ursache Lösung
CAPTCHA-Bild lädt nicht Session-Cookie abgelaufen Neue Sitzung starten
„Sitzung abgelaufen“ im Formular Lösung hat zu lange gedauert Direkt vor dem Absenden lösen
Falsche CAPTCHA-Antwort Verzerrtes Bild Schlechtes Bild über die API melden
Portal blockiert Automatisierung IP-/UA-Erkennung Residential-Proxy + echten User-Agent nutzen
Formularfehler nach dem CAPTCHA Serverseitiges Token abgelaufen CAPTCHA unmittelbar vor dem Absenden lösen

FAQ

Welche CAPTCHA-Typen auf Behördenportalen löst CaptchaAI?

Die auf Behördenseiten üblichen: reCAPTCHA v2 (inklusive Invisible und Enterprise), klassische Bild- und OCR-CAPTCHAs, Grid-Image sowie BLS. Auch Cloudflare Turnstile und GeeTest v3 werden unterstützt. hCaptcha und FunCaptcha lösen wir nicht – auf reinen Behördenportalen begegnen Ihnen diese Typen aber ohnehin selten.

Löst CaptchaAI auch BLS-CAPTCHAs für Visa-Termine?

Ja. CaptchaAI verarbeitet BLS-CAPTCHAs mit hoher Erfolgsquote – entweder direkt über method=bls oder über die Bild-Route mit method=base64, wie im Code oben gezeigt. Gerade für DACH-Antragstellende, die regelmäßig auf Termine prüfen, ist das der praxisnahe Weg.

Was kostet das Lösen von Behörden-CAPTCHAs?

CaptchaAI rechnet nach gleichzeitigen Threads ab, nicht pro Lösung. Der Einstieg BASIC kostet 15 $/Monat und umfasst 5 Threads mit unbegrenzten Lösungen im Abrechnungsmonat. Für einzelne Terminprüfungen oder kleine Register-Läufe reicht das meist; erst bei paralleler Massenabfrage lohnt ein größerer Tarif.

Wie gehe ich mit kurzen Session-Timeouts um?

Halten Sie den Ablauf schlank und lösen Sie das CAPTCHA möglichst spät. Ein Sticky-Proxy mit fester IP über die gesamte Sitzung verhindert zusätzlich, dass das Portal einen IP-Wechsel zwischen den Formularseiten als Bruch wertet und die Sitzung verwirft.

Ist die Automatisierung eigener Behördenvorgänge rechtlich zulässig?

Das Automatisieren eigener Formulare und die Abfrage öffentlicher Daten ist grundsätzlich zulässig, ebenso QA-Tests für Civic-Tech-Anwendungen. Prüfen Sie aber immer die Nutzungsbedingungen des konkreten Portals und – bei personenbezogenen Datensätzen – Ihre DSGVO-Rechtsgrundlage.


Verwandte Leitfäden


Nächste Schritte

Kommentare sind für diesen Artikel deaktiviert.