Anwendungsfälle

Formulare mit CAPTCHA automatisch absenden

Ja, CAPTCHA-geschützte Formulare lassen sich automatisch absenden – reCAPTCHA v2, Cloudflare Turnstile und Bild-CAPTCHAs inklusive. Der Ablauf ist immer gleich: Selenium trägt die Felder ein, CaptchaAI löst die Abfrage und liefert das Token, Ihr Skript sendet ab. Dieser Leitfaden zeigt die drei Bausteine und ein lauffähiges Beispiel.


Warum CAPTCHAs Formulare blockieren

Ein CAPTCHA-geschütztes Formular akzeptiert die Übermittlung erst mit gültigem Token – reine Selenium-Automatisierung kommt nicht mehr durch. Solche Schutzmechanismen sitzen genau an den Stellen, die QA-Teams am häufigsten testen: Kontaktformulare, Login- und Registrierungsseiten, Warenkorb- und Checkout-Schritte oder Terminportale. Für Teams in der DACH-Region ist das Alltag – etwa beim Regressionstest eines Anmeldeformulars in der eigenen Staging-Umgebung oder beim Prüfen eines Shopware- oder JTL-Checkouts.

CaptchaAI übernimmt dabei genau einen Schritt: Es nimmt Sitekey und Seiten-URL entgegen, löst die Abfrage und gibt ein Token zurück, das Ihr Skript in das versteckte Antwortfeld einträgt. Abgedeckt sind reCAPTCHA v2, Cloudflare Turnstile und Bild-CAPTCHAs; hCaptcha und FunCaptcha werden nicht unterstützt. Da Formulardaten oft personenbezogen sind, testen Sie nur gegen eigene oder freigegebene Endpunkte und prüfen die DSGVO-Grundlage Ihrer Datenflüsse.


Voraussetzungen

Für den Workflow brauchen Sie drei Dinge: einen CaptchaAI-API-Schlüssel aus Ihrem Konto auf captchaai.com, eine Python-Umgebung mit Selenium und requests sowie einen Chrome-Browser mit passendem Treiber. Die Abrechnung erfolgt Thread-basiert – ein Thread löst ein CAPTCHA nach dem anderen, ohne Limit pro Lösung. Für einzelne Formular-Tests reicht daher meist der kleinste Tarif; erst parallele Läufe über viele Formulare hinweg profitieren von mehr Threads.

Halten Sie den API-Schlüssel außerhalb des Codes, etwa in einer Umgebungsvariablen, damit er nicht versehentlich in Ihr Repository gelangt.


So läuft der Formular-Workflow ab

Der Ablauf besteht aus vier Schritten, die sich für jedes Formular wiederholen – vom Laden der Seite bis zum Absenden:

┌────────────┐     ┌──────────────┐     ┌────────────┐     ┌──────────────┐
│ Load Form  │────▶│ Fill Fields  │────▶│ Detect &   │────▶│ Submit Form  │
│ (Selenium) │     │              │     │ Solve      │     │              │
│            │     │              │     │ CAPTCHA    │     │              │
└────────────┘     └──────────────┘     └────────────┘     └──────────────┘

Die drei Bausteine der Automatisierung

Der Code teilt sich in drei Klassen, die aufeinander aufbauen: die CaptchaAI-Anbindung, die Typerkennung und der Formularablauf, der beide zusammenführt.

Baustein 1: CAPTCHA an CaptchaAI übergeben

Der Löser übermittelt die Abfrage per POST an in.php und erhält eine Task-ID. Danach fragt er res.php im Abstand von wenigen Sekunden ab (Polling), bis das Token vorliegt oder das Timeout greift. Das anfängliche initial_wait gibt CaptchaAI Zeit für die erste Lösung, bevor überhaupt das erste Ergebnis abgefragt wird.

import time
import requests


class FormCaptchaSolver:
    BASE = "https://ocr.captchaai.com"

    def __init__(self, api_key):
        self.api_key = api_key

    def solve(self, params, initial_wait=10):
        params["key"] = self.api_key
        params["json"] = 1
        resp = requests.post(f"{self.BASE}/in.php", data=params).json()
        if resp["status"] != 1:
            raise Exception(f"Submit error: {resp['request']}")

        task_id = resp["request"]
        time.sleep(initial_wait)

        for _ in range(60):
            result = requests.get(
                f"{self.BASE}/res.php",
                params={"key": self.api_key, "action": "get", "id": task_id, "json": 1},
            ).json()
            if result["request"] == "CAPCHA_NOT_READY":
                time.sleep(5)
                continue
            if result["status"] == 1:
                return result["request"]
            raise Exception(f"Solve error: {result['request']}")
        raise TimeoutError("CAPTCHA solve timed out")

Baustein 2: CAPTCHA-Typ erkennen

Der Detektor liest den DOM der aktuellen Seite aus und meldet Typ und Sitekey. Die Reihenfolge ist entscheidend: Turnstile wird vor reCAPTCHA geprüft, weil beide das Attribut data-sitekey verwenden. Findet sich kein Widget, sucht der Detektor nach einem Bild-CAPTCHA und liefert dessen URL zurück.

import re
from selenium.webdriver.common.by import By


class CaptchaDetector:
    def __init__(self, driver):
        self.driver = driver

    def detect(self):
        """Detect CAPTCHA type on current page."""
        html = self.driver.page_source

        # Turnstile
        turnstile = self.driver.find_elements(By.CSS_SELECTOR, ".cf-turnstile, [data-sitekey]")
        for el in turnstile:
            if "cf-turnstile" in (el.get_attribute("class") or ""):
                return "turnstile", el.get_attribute("data-sitekey")

        # reCAPTCHA
        recaptcha = self.driver.find_elements(By.CSS_SELECTOR, "[data-sitekey]")
        if recaptcha:
            sitekey = recaptcha[0].get_attribute("data-sitekey")
            if "recaptcha" in html.lower():
                return "recaptcha_v2", sitekey

        # Image CAPTCHA
        img = self.driver.find_elements(By.CSS_SELECTOR, "img[src*='captcha'], img.captcha")
        if img:
            return "image", img[0].get_attribute("src")

        return "none", None

Baustein 3: Felder ausfüllen und absenden

Der Formularautomat verbindet Detektor und Löser: Er füllt die sichtbaren Felder, ermittelt den CAPTCHA-Typ, ruft die passende Löser-Methode auf und trägt das Token in das versteckte Antwortfeld ein – bei reCAPTCHA in g-recaptcha-response, bei Turnstile in cf-turnstile-response. Erst danach klickt er die Absenden-Schaltfläche.

import base64
import requests as req
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class FormAutomator:
    def __init__(self, api_key):
        self.solver = FormCaptchaSolver(api_key)
        self.driver = webdriver.Chrome()
        self.detector = CaptchaDetector(self.driver)

    def fill_field(self, selector, value):
        field = WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, selector))
        )
        field.clear()
        field.send_keys(value)

    def select_option(self, selector, value):
        from selenium.webdriver.support.ui import Select
        select = Select(self.driver.find_element(By.CSS_SELECTOR, selector))
        select.select_by_value(value)

    def solve_captcha(self):
        captcha_type, data = self.detector.detect()
        page_url = self.driver.current_url

        if captcha_type == "recaptcha_v2":
            token = self.solver.solve({
                "method": "userrecaptcha",
                "googlekey": data,
                "pageurl": page_url,
            })
            self.driver.execute_script(
                f'document.querySelector("[name=g-recaptcha-response]").value = "{token}";'
            )
            return True

        if captcha_type == "turnstile":
            token = self.solver.solve({
                "method": "turnstile",
                "sitekey": data,
                "pageurl": page_url,
            })
            self.driver.execute_script(
                f'document.querySelector("[name=cf-turnstile-response]").value = "{token}";'
            )
            return True

        if captcha_type == "image":
            img_data = req.get(data).content
            img_b64 = base64.b64encode(img_data).decode()
            text = self.solver.solve({"method": "base64", "body": img_b64})
            captcha_input = self.driver.find_element(
                By.CSS_SELECTOR, "input[name*='captcha']"
            )
            captcha_input.clear()
            captcha_input.send_keys(text)
            return True

        return False  # No CAPTCHA detected

    def submit_form(self, url, fields, submit_selector="button[type='submit']"):
        """
        fields: list of (selector, value) tuples
        """
        self.driver.get(url)

        for selector, value in fields:
            self.fill_field(selector, value)

        self.solve_captcha()

        submit = self.driver.find_element(By.CSS_SELECTOR, submit_selector)
        submit.click()

        return self.driver.current_url

    def close(self):
        self.driver.quit()

Praxisbeispiel: Kontaktformular absenden

Ein einziger submit_form()-Aufruf bündelt den kompletten Ablauf. Die Felder übergeben Sie als Liste aus CSS-Selektor und Wert; das CAPTCHA wird automatisch erkannt und unmittelbar vor dem Klick gelöst:

automator = FormAutomator("YOUR_API_KEY")

try:
    result_url = automator.submit_form(
        url="https://example.com/contact",
        fields=[
            ("#name", "John Doe"),
            ("#email", "john@example.com"),
            ("#subject", "Sales inquiry"),
            ("#message", "I'd like to learn more about your services."),
        ],
        submit_selector="#submit-btn",
    )
    print(f"Form submitted. Redirected to: {result_url}")
finally:
    automator.close()

Weitere Formulartypen abdecken

Dasselbe Muster trägt für praktisch jeden Formulartyp – nur Selektoren und Feldwerte ändern sich. Ob Login, Registrierung oder eine geschützte Suche: Der Automat erkennt das CAPTCHA selbst und braucht keine typ-spezifische Sonderbehandlung.

Login-Formular

result = automator.submit_form(
    url="https://example.com/login",
    fields=[
        ("#username", "testuser"),
        ("#password", "testpass123"),
    ],
    submit_selector="#login-btn",
)

Registrierung

result = automator.submit_form(
    url="https://example.com/register",
    fields=[
        ("#first-name", "Jane"),
        ("#last-name", "Smith"),
        ("#email", "jane@example.com"),
        ("#password", "SecurePass!123"),
        ("#confirm-password", "SecurePass!123"),
    ],
    submit_selector="#register-btn",
)

Suchformular mit CAPTCHA-Schutz

result = automator.submit_form(
    url="https://example.com/search",
    fields=[
        ("#query", "python developer"),
        ("#location", "San Francisco"),
    ],
    submit_selector="#search-btn",
)

AJAX- und JavaScript-Formulare behandeln

Viele moderne Formulare senden nicht per klassischem POST, sondern über einen XHR- oder fetch-Aufruf. Dann füllen Sie kein verstecktes Feld, sondern fügen das gelöste Token direkt in die Anfragedaten ein, die das JavaScript verschickt. Bei reCAPTCHA mit Callback rufen Sie nach dem Eintragen zusätzlich grecaptcha.execute() auf, damit die Seite den Wert übernimmt. Im Netzwerk-Tab der Entwicklerwerkzeuge sehen Sie, unter welchem Feldnamen der Token-Wert erwartet wird.


Bewährte Praktiken für stabile Formular-Workflows

Ein gelöstes Token ist nur rund 120 Sekunden gültig – lösen Sie das CAPTCHA deshalb als letzten Schritt und senden Sie sofort ab. Setzen Sie statt fester Pausen explizite Waits (WebDriverWait), damit dynamisch nachgeladene Felder zuverlässig gefunden werden. Fangen Sie vorübergehende Fehler mit einer Wiederholungslogik und exponentiellem Backoff ab und respektieren Sie das Rate-Limiting der Zielseite. Für dauerhafte Läufe bieten sich deutsche Infrastruktur-Anbieter wie Hetzner oder netcup und eine GitLab-CI-Pipeline an, in der die Tests reproduzierbar gegen Ihre Staging-Umgebung laufen.


Typische Fehler und ihre Lösung

Problem Ursache Lösung
Token abgelehnt Token vor der Übermittlung abgelaufen CAPTCHA zuletzt lösen, sofort absenden
Feld nicht gefunden Dynamisches Laden der Seite Explizite Wartezeiten ergänzen
Falscher CAPTCHA-Typ erkannt Mehrere CAPTCHA-Elemente Erkennungsreihenfolge prüfen
Formular lädt nach dem Absenden neu Serverseitige Validierung fehlgeschlagen Alle Pflichtfelder prüfen
reCAPTCHA-Callback nicht ausgelöst Callback muss aufgerufen werden grecaptcha.execute() nach dem Eintragen aufrufen

Häufige Fragen

Welche CAPTCHA-Typen deckt dieser Formular-Workflow ab?

reCAPTCHA v2, Cloudflare Turnstile und Bild-CAPTCHAs (OCR). reCAPTCHA v3 und GeeTest v3 lassen sich mit demselben Muster ergänzen; hCaptcha und FunCaptcha werden nicht unterstützt.

Wie lange ist ein gelöstes CAPTCHA-Token gültig?

Rund 120 Sekunden. Lösen Sie das CAPTCHA deshalb zuletzt und tragen Sie das Token unmittelbar vor dem Absenden ein.

Was kostet das automatische Lösen von Formular-CAPTCHAs?

CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung. BASIC kostet 15 $ pro Monat mit 5 Threads und unbegrenzten Lösungen; STANDARD liegt bei 30 $ mit 15 Threads. Für einzelne Formular-Workflows genügt meist BASIC.

Brauche ich für jedes Formular einen echten Browser?

Nicht zwingend: reCAPTCHA v2 und Turnstile lassen sich rein per HTTP-Request lösen und das Token per POST übermitteln. Nur clientseitige JavaScript-Validierung erzwingt einen echten Browser wie in den Beispielen oben.

Ist die automatisierte Formularübermittlung mit CAPTCHA erlaubt?

Für eigene oder ausdrücklich freigegebene Formulare – etwa in QA, Monitoring oder Integrationstests – ist das üblich und zulässig. Automatisieren Sie keine fremden, zugangsbeschränkten Systeme ohne Erlaubnis und prüfen Sie bei personenbezogenen Daten Ihre DSGVO-Grundlage.


Weiterführende Leitfäden


Automatisieren Sie jedes Formular – CAPTCHAs mit CaptchaAI lösen.

Kommentare sind für diesen Artikel deaktiviert.