Anwendungsfälle

CAPTCHA-Handling für die Suche in öffentlichen Registern

Registerabfragen scheitern selten an der Suchmaske, sondern am verzerrten Bild-CAPTCHA davor. Der Ablauf dahinter ist kurz: das CAPTCHA-Bild in derselben Sitzung laden, als Base64 an in.php übermitteln, das Ergebnis abfragen und den erkannten Text zusammen mit den Formulardaten absenden. Alles Weitere ist Session-Hygiene – Cookies behalten, versteckte Formularfelder mitschicken, Weiterleitungen zulassen.

Dieser Leitfaden ordnet die gängigen CAPTCHA-Typen den Portalkategorien zu, zeigt den Ablauf in Python und JavaScript und nennt die Parameter, mit denen die Texterkennung auch bei schlechten Vorlagen stabil bleibt.

Welche CAPTCHA-Typen in Registerportalen auftauchen

Behördliche Auskunftssysteme sind selten auf dem neuesten Stand: Statt reCAPTCHA oder Cloudflare Turnstile läuft dort oft ein selbst gebautes Bild-CAPTCHA, das seit der Inbetriebnahme unverändert ist.

Portalkategorie Typisches CAPTCHA Beispiel für die Abfrage
Gerichtsaktensuche eigenes Text-CAPTCHA verzerrte alphanumerische Folge, 5–6 Zeichen
Grundbuch- und Katasterauskunft Mathe-CAPTCHA „Was ist 4 + 7?“
Handels- und Unternehmensregister Bild-Text-CAPTCHA verzogene Buchstaben mit Linienrauschen
Personenstandsregister reCAPTCHA v2 Auswahl im Bildraster
Baugenehmigungen einfaches Text-CAPTCHA vierstelliger Zahlencode
UCC-Einträge (US) eigenes OCR-CAPTCHA Groß- und Kleinschreibung mit Hintergrundrauschen

In der DACH-Region ist die Portallandschaft ähnlich fragmentiert: Handelsregister, Vereinsregister, Grundbuchauskunft der Länder und kommunale Ratsinformationssysteme laufen auf sehr unterschiedlichen Plattformen – entsprechend unterschiedlich fällt der Schutz der Suchmaske aus. Prüfen Sie jedes Portal einzeln.

Vor dem ersten Skript: den Rahmen klären

Registerdaten sind öffentlich zugänglich, aber nicht beliebig verwertbar. Vier Punkte, die in Rechercheprojekten regelmäßig zu Nacharbeit führen:

  • Nutzungsbedingungen. Viele Auskunftsportale erlauben die Einzelabfrage, untersagen aber den systematischen Abruf oder die Weiterverwertung ganzer Bestände. Das steht in den AGB oder in den Hinweisen zur Nutzung.
  • DSGVO. Namen, Anschriften und Geburtsdaten aus Registern sind personenbezogene Daten – ebenso die IP-Adressen in Ihren eigenen Logs. Rechtsgrundlage, Speicherdauer und Löschkonzept gehören geklärt, bevor der erste Datensatz abgelegt wird.
  • Gebührenpflichtige Abrufe. Einzelne Auskünfte kosten Geld. Ein Skript, das unbesehen auf „Dokument abrufen“ klickt, erzeugt reale Kosten – trennen Sie Suche und Abruf sauber voneinander.
  • Abfragetempo. Viele Portale laufen auf kleiner Infrastruktur; eine Pause von einigen Sekunden je Suche entscheidet oft darüber, ob ein Lauf bis zum Ende durchkommt.

Bild-CAPTCHAs im Suchformular lösen

Der Ablauf ist bei fast allen Portalen identisch:

  1. Suchseite laden und die Sitzung samt Cookies behalten.
  2. Die Bild-URL aus dem HTML lesen – meist id="captchaImage", eine Klasse captcha oder schlicht ein src, in dem „captcha“ vorkommt.
  3. Das Bild mit derselben Sitzung herunterladen und als Base64 an CaptchaAI übermitteln.
  4. Den erkannten Text zusammen mit Suchbegriff und versteckten Formularfeldern absenden.

Die folgende Klasse kapselt genau diese vier Schritte für eine Gerichtsaktensuche:

import requests
import base64
import time
from urllib.parse import urljoin

class PublicRecordsSearcher:
    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 search_court_records(self, portal_url, case_number):
        """Search court records, solving image CAPTCHAs as needed."""
        # Load the search page
        page = self.session.get(f"{portal_url}/search")

        # Extract CAPTCHA image
        captcha_img_url = self._extract_captcha_url(page.text, portal_url)
        if not captcha_img_url:
            # No CAPTCHA on this page
            return self._submit_search(portal_url, case_number)

        # Download and solve CAPTCHA
        img_response = self.session.get(captcha_img_url)
        captcha_text = self._solve_image_captcha(img_response.content)

        # Submit search with solved CAPTCHA
        return self._submit_search(portal_url, case_number, captcha_text)

    def _extract_captcha_url(self, html, base_url):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")

        # Look for common CAPTCHA image patterns
        captcha_img = (
            soup.find("img", {"id": "captchaImage"}) or
            soup.find("img", {"class": "captcha"}) or
            soup.find("img", attrs={"src": lambda s: s and "captcha" in s.lower()})
        )

        if captcha_img and captcha_img.get("src"):
            return urljoin(base_url, captcha_img["src"])
        return None

    def _solve_image_captcha(self, image_bytes):
        img_base64 = base64.b64encode(image_bytes).decode("utf-8")

        resp = requests.post("https://ocr.captchaai.com/in.php", data={
            "key": self.api_key,
            "method": "base64",
            "body": img_base64,
            "json": 1
        })
        task_id = resp.json()["request"]

        for _ in range(30):
            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 _submit_search(self, portal_url, case_number, captcha_text=None):
        form_data = {"caseNumber": case_number}
        if captcha_text:
            form_data["captcha"] = captcha_text

        response = self.session.post(
            f"{portal_url}/search/results",
            data=form_data
        )
        return response.text

# Usage
searcher = PublicRecordsSearcher("YOUR_API_KEY")
results = searcher.search_court_records(
    "https://courts.example.gov",
    "2024-CV-12345"
)

Entscheidend ist die gemeinsame requests.Session: Ein Bild, das ohne Cookie oder mit einem zweiten Client geladen wird, gehört zu einer anderen Sitzung als das Formular – die Antwort ist dann auch bei einwandfreier Erkennung falsch.

Mathe-CAPTCHAs: rechnen statt erkennen

Manche Portale zeigen keine Zeichenfolge, sondern eine kleine Rechenaufgabe als Bild. Für die API bleibt das Texterkennung; nur die Anweisung ändert sich. Mit textinstructions fordern Sie das Ergebnis der Rechnung an und nicht die abgebildeten Zeichen.

def solve_math_captcha(self, image_bytes):
    """Solve math CAPTCHAs like '4 + 7 = ?'"""
    img_base64 = base64.b64encode(image_bytes).decode("utf-8")

    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": self.api_key,
        "method": "base64",
        "body": img_base64,
        "textinstructions": "solve the math equation and return only the number",
        "json": 1
    })
    task_id = resp.json()["request"]

    # Poll for result
    for _ in range(30):
        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("Math CAPTCHA solve timed out")

Steht die Aufgabe als reiner HTML-Text im Seitenquelltext statt als Bild, brauchen Sie gar keinen Solver: Dann genügen ein regulärer Ausdruck und eine Addition im eigenen Code.

Mehrere Portale in einem Durchlauf abfragen

Recherchen enden selten bei einer Quelle. Wer denselben Namen im Unternehmensregister, in der Gerichtsaktensuche und im Grundbuchportal sucht, braucht eine Schleife, die Fehler pro Portal protokolliert, statt den ganzen Lauf abzubrechen.

class RecordsAggregator {
  constructor(apiKey) {
    this.apiKey = apiKey;
  }

  async searchAcrossPortals(query, portals) {
    const results = [];

    for (const portal of portals) {
      try {
        const data = await this.searchPortal(portal, query);
        results.push({ portal: portal.name, records: data });
      } catch (error) {
        results.push({ portal: portal.name, error: error.message });
      }
    }

    return results;
  }

  async searchPortal(portal, query) {
    const pageResponse = await fetch(portal.searchUrl);
    const html = await pageResponse.text();

    // Check for image CAPTCHA
    const captchaMatch = html.match(/captcha[^"]*\.(?:png|jpg|gif)/i);
    let captchaAnswer = null;

    if (captchaMatch) {
      const imgUrl = new URL(captchaMatch[0], portal.searchUrl).href;
      const imgData = await fetch(imgUrl);
      const buffer = await imgData.arrayBuffer();
      const base64 = Buffer.from(buffer).toString('base64');

      captchaAnswer = await this.solveImageCaptcha(base64);
    }

    // Submit search
    const formData = new URLSearchParams({ q: query });
    if (captchaAnswer) formData.append('captcha', captchaAnswer);

    const response = await fetch(portal.searchUrl, {
      method: 'POST',
      body: formData
    });

    return response.text();
  }

  async solveImageCaptcha(base64Image) {
    const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
      method: 'POST',
      body: new URLSearchParams({
        key: this.apiKey,
        method: 'base64',
        body: base64Image,
        json: '1'
      })
    });

    const { request: taskId } = await submitResp.json();

    for (let i = 0; i < 30; i++) {
      await new Promise(r => setTimeout(r, 3000));
      const result = await fetch(
        `https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
      );
      const data = await result.json();
      if (data.status === 1) return data.request;
    }

    throw new Error('CAPTCHA solve timed out');
  }
}

// Usage
const aggregator = new RecordsAggregator('YOUR_API_KEY');
const results = await aggregator.searchAcrossPortals('Smith LLC', [
  { name: 'State Business Registry', searchUrl: 'https://sos.example.gov/search' },
  { name: 'County Court Records', searchUrl: 'https://courts.example.gov/search' }
]);

Das Muster ist bewusst sequenziell: Paralleles Abfragen derselben Quelle provoziert Rate-Limiting; parallelisieren lohnt sich erst über verschiedene Portale hinweg.

Erkennungsparameter richtig setzen

Je genauer Sie das erwartete Format beschreiben, desto stabiler fällt die Erkennung aus.

Parameter Wert Wann sinnvoll
method base64 Bild wurde als Bytes heruntergeladen
method post Bilddatei wird direkt übermittelt
language 0 Text-CAPTCHAs mit lateinischen Zeichen
numeric 1 CAPTCHAs, die nur aus Ziffern bestehen
min_len / max_len portalabhängig wenn die Zeichenzahl vorhersehbar ist
textinstructions eigene Anweisung Rechenaufgaben oder feste Formate

Bei sehr schlechten Vorlagen hilft zusätzlich eine Vorverarbeitung des Bildes: Graustufen, mehr Kontrast, Rauschen entfernen. Die Anleitung zur Bildvorverarbeitung beschreibt die einzelnen Schritte.

Wenn die Suche fehlschlägt

Symptom Ursache Abhilfe
CAPTCHA-Bild liefert 403 Sitzungscookie fehlt erst die Suchseite laden, dann das Bild abrufen
Antwort wird abgelehnt schlechte Bildqualität Bild vorverarbeiten oder min_len / max_len setzen
Beim Absenden erscheint ein neues CAPTCHA Formular-Token abgelaufen versteckte Formularfelder im selben Request wie das Bild auslesen
Trefferliste bleibt leer POST-Weiterleitung verliert Cookies allow_redirects=True nutzen und die Sitzung beibehalten

Durchsatz und Kosten einplanen

CaptchaAI rechnet Thread-basiert ab, nicht pro Lösung: Ein Thread ist eine gleichzeitig laufende CAPTCHA-Anfrage; die Zahl der Lösungen ist innerhalb des Tarifs nicht gedeckelt. Für Registerrecherchen zählt also die Parallelität, nicht die Gesamtzahl der geprüften Fälle.

  • BASIC (15 $ pro Monat, 5 Threads) – sequenzielle Recherchen mit ein bis zwei parallelen Quellen.
  • ADVANCE (90 $ pro Monat, 50 Threads) – nächtliche Sammelläufe über viele Portale.
  • ENTERPRISE (300 $ pro Monat, 200 Threads) – Dauerbetrieb mit mehreren Rechercheteams.

Preise in US-Dollar. Bild-CAPTCHAs löst der Dienst laut den veröffentlichten Solver-Angaben in unter 0,5 Sekunden – der Engpass liegt in der Praxis beim Portal selbst.

Häufige Fragen

Welche CAPTCHA-Typen deckt CaptchaAI auf Registerportalen ab?

Bild- und OCR-CAPTCHAs (über 27.500 Varianten), Rasterbild-CAPTCHAs, reCAPTCHA v2 und v3 inklusive Enterprise, Cloudflare Turnstile, Cloudflare Challenge und GeeTest v3. hCaptcha und FunCaptcha werden nicht unterstützt, GeeTest v4 ist bislang nur als „bald verfügbar“ angekündigt. CaptchaFox, Friendly Captcha und Lemin laufen als Beta.

Wie oft darf ein Registerportal abgefragt werden?

So selten wie möglich und nur im Rahmen der Nutzungsbedingungen. Bewährt hat sich ein sequenzieller Lauf mit mehreren Sekunden Abstand statt paralleler Anfragen an dieselbe Quelle; große Sammelläufe legen Sie besser in die Nachtstunden.

Nach dem Absenden erscheint erneut ein CAPTCHA – woran liegt das?

Meist ist das Formular-Token abgelaufen oder die Sitzung ist zwischen Bildabruf und POST verloren gegangen. Lesen Sie alle versteckten Felder im selben Request aus, mit dem Sie das CAPTCHA-Bild holen, und senden Sie sie unverändert mit.

Brauche ich einen Browser oder reichen HTTP-Anfragen?

Für klassische Bild-CAPTCHAs reichen HTTP-Anfragen mit persistenter Sitzung – das ist schneller und weniger fehleranfällig als jede Browsersteuerung. Erst wenn ein Portal reCAPTCHA v2 oder Turnstile einsetzt und das Token per JavaScript in die Seite schreibt, lohnen sich Selenium oder Playwright.

Wie gehe ich mit den erhobenen Personendaten um?

Wie jede andere personenbezogene Verarbeitung: dokumentierte Rechtsgrundlage, minimaler Umfang, feste Löschfristen. Dass die Daten aus einem öffentlichen Register stammen, macht ihre Speicherung im eigenen System nicht automatisch zulässig.

Nächste Schritte

Holen Sie sich Ihren CaptchaAI-API-Schlüssel und lösen Sie das erste Register-CAPTCHA direkt aus Ihrem Recherche-Skript – ohne die Suchmaske manuell zu bedienen.


Verwandte Leitfäden

Kommentare sind für diesen Artikel deaktiviert.