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
- Vom ersten CAPTCHA bis zum Produktivbetrieb
- API-Kurzreferenz auf einen Blick
Automatisieren Sie jedes Formular – CAPTCHAs mit CaptchaAI lösen.