Sobald eine Selenium-Automatisierung auf ein reCAPTCHA oder eine Cloudflare-Turnstile-Abfrage trifft, bleibt sie stehen – der Browser wartet auf eine Eingabe, die nie kommt. Die Lösung ist eine klare Arbeitsteilung: Selenium steuert Browser und Formular, CaptchaAI löst die CAPTCHA-Abfrage über die API und liefert ein gültiges Token zurück. Dieser Leitfaden zeigt das komplette Integrationsmuster für reCAPTCHA v2 und v3, Cloudflare Turnstile und Bild-CAPTCHAs – vom Erkennen des Typs bis zum abgesendeten Formular.
Voraussetzungen
Sie brauchen drei Pakete: Selenium für die Browsersteuerung, requests für die HTTP-Aufrufe an die CaptchaAI-API und webdriver-manager, damit der passende ChromeDriver automatisch installiert wird.
pip install selenium requests webdriver-manager
Selenium einrichten und konfigurieren
Der folgende Treiber startet Chrome mit ein paar reduzierten Automatisierungs-Flags, damit sich die Sitzung wie ein normaler Browser verhält. Das ist keine aufwendige Sonderkonfiguration, sondern eine saubere Standardbasis für automatisierte Tests.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def create_driver():
"""Create a Selenium driver for CAPTCHA automation."""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options,
)
return driver
CaptchaAI Solver-Helfer
Statt für jeden CAPTCHA-Typ eigenen Code zu schreiben, kapseln Sie den API-Ablauf in einer einzigen Funktion. Sie übermittelt die Aufgabe an in.php, fragt das Ergebnis anschließend per Polling über res.php ab und gibt das fertige Token zurück. Dieselbe Funktion bedient reCAPTCHA, Turnstile und Bild-CAPTCHAs – es ändert sich nur der method-Parameter.
import time
import requests
API_KEY = "YOUR_API_KEY"
def solve_captcha(method, **params):
"""Generic CaptchaAI solver — works for all supported CAPTCHA types."""
submit_data = {
"key": API_KEY,
"method": method,
"json": 1,
**params,
}
submit = requests.post("https://ocr.captchaai.com/in.php", data=submit_data, timeout=30)
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=30).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
raise Exception("CAPTCHA unsolvable")
raise TimeoutError("Solve timed out")
reCAPTCHA v2 in Selenium lösen
reCAPTCHA v2 ist der häufigste Fall. Der Ablauf ist immer gleich: Sitekey aus der Seitenquelle extrahieren, über CaptchaAI lösen, das zurückgegebene Token in das versteckte Feld g-recaptcha-response schreiben und – falls vorhanden – die Callback-Funktion auslösen. Erst danach wird das Formular abgesendet.
Kompletter Ablauf: erkennen, lösen, Token einfügen, absenden
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
def solve_recaptcha_v2_selenium(driver, url):
"""Complete reCAPTCHA v2 solve in Selenium."""
driver.get(url)
# Wait for page to load
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Extract sitekey
page_source = driver.page_source
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', page_source)
if not match:
raise ValueError("reCAPTCHA sitekey not found")
sitekey = match.group(1)
print(f"Sitekey: {sitekey}")
# Solve via CaptchaAI
token = solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
)
print(f"Token received: {token[:50]}...")
# Inject token into the page
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
document.getElementById('g-recaptcha-response').style.display = 'block';
""")
# If there's a callback function, call it
driver.execute_script(f"""
if (typeof ___grecaptcha_cfg !== 'undefined') {{
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {{
var client = clients[key];
if (client.rr && client.rr.l) {{
client.rr.l.callback('{token}');
}}
}}
}}
""")
# Submit the form
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], input[type='submit']")
submit_button.click()
return token
# Usage
driver = create_driver()
try:
solve_recaptcha_v2_selenium(driver, "https://example.com/login")
print(f"Current URL: {driver.current_url}")
finally:
driver.quit()
Cloudflare Turnstile in Selenium lösen
Turnstile funktioniert nach demselben Prinzip, nur heißt das Antwortfeld cf-turnstile-response und der API-method lautet turnstile. Den Sitekey finden Sie entweder im data-sitekey-Attribut oder in der JavaScript-Konfiguration des Widgets.
def solve_turnstile_selenium(driver, url):
"""Complete Turnstile solve in Selenium."""
driver.get(url)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Extract sitekey
page_source = driver.page_source
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', page_source)
if not match:
# Try JavaScript API pattern
match = re.search(r"sitekey\s*:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", page_source)
if not match:
raise ValueError("Turnstile sitekey not found")
sitekey = match.group(1)
print(f"Turnstile sitekey: {sitekey}")
# Solve via CaptchaAI
token = solve_captcha(
"turnstile",
sitekey=sitekey,
pageurl=url,
)
print(f"Turnstile token: {token[:50]}...")
# Inject token
driver.execute_script(f"""
// Set the hidden input value
var inputs = document.querySelectorAll('[name="cf-turnstile-response"]');
inputs.forEach(function(input) {{ input.value = '{token}'; }});
// Also try the callback approach
if (typeof turnstile !== 'undefined' && turnstile.getResponse) {{
// Widget already rendered
}}
""")
# Submit form
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], input[type='submit']")
submit_button.click()
return token
Bild-CAPTCHAs in Selenium lösen
Für klassische Bild- oder Text-CAPTCHAs, bei denen die angezeigten Zeichen eingetippt werden, genügt ein Screenshot des Elements. Selenium liefert ihn direkt als Base64, der an die CaptchaAI-API geht:
import base64
def solve_image_captcha_selenium(driver, captcha_selector):
"""Solve image CAPTCHA visible in the browser."""
# Find the CAPTCHA image element
captcha_img = driver.find_element(By.CSS_SELECTOR, captcha_selector)
# Get image as base64
img_base64 = captcha_img.screenshot_as_base64
# Solve via CaptchaAI
answer = solve_captcha("base64", body=img_base64)
print(f"CAPTCHA answer: {answer}")
# Type the answer into the input field
captcha_input = driver.find_element(
By.CSS_SELECTOR, "input[name='captcha'], input[name='code'], input.captcha-input"
)
captcha_input.clear()
captcha_input.send_keys(answer)
return answer
reCAPTCHA v3 in Selenium lösen
reCAPTCHA v3 zeigt kein anklickbares Widget, sondern vergibt im Hintergrund einen Score. Sie übergeben zusätzlich version="v3" und die passende action; das zurückgegebene Token wird genauso in g-recaptcha-response geschrieben.
def solve_recaptcha_v3_selenium(driver, url, sitekey, action="verify"):
"""Solve reCAPTCHA v3 in Selenium."""
driver.get(url)
# Solve via CaptchaAI
token = solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
version="v3",
action=action,
)
# Inject token
driver.execute_script(f"""
// Set reCAPTCHA response
var textarea = document.getElementById('g-recaptcha-response');
if (textarea) {{
textarea.value = '{token}';
textarea.style.display = 'block';
}}
// Set any hidden input fields
var inputs = document.querySelectorAll('input[name="g-recaptcha-response"]');
inputs.forEach(function(input) {{ input.value = '{token}'; }});
""")
return token
Vollständiges Automatisierungsbeispiel
In der Praxis wissen Sie oft nicht im Voraus, welcher CAPTCHA-Typ auf einer Seite erscheint. Die Klasse SeleniumCaptchaSolver erkennt den Typ automatisch aus der Seitenquelle, wählt den passenden Lösungsweg und füllt anschließend das restliche Formular aus.
Solche Skripte laufen selten lokal: Meist arbeiten sie auf einem VPS – etwa einer Hetzner-Cloud-Instanz –, der mehrere Selenium-Sitzungen parallel abarbeitet. Wenn Sie dabei personenbezogene Daten erfassen, prüfen Sie vorab Ihre Rechtsgrundlage nach DSGVO; schon eine IP-Adresse gilt als personenbezogenes Datum.
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
import re
import time
import requests
API_KEY = "YOUR_API_KEY"
class SeleniumCaptchaSolver:
"""Complete Selenium + CaptchaAI automation class."""
def __init__(self, api_key):
self.api_key = api_key
self.driver = None
def start(self):
"""Initialize the browser."""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
self.driver = webdriver.Chrome(options=options)
self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
def stop(self):
"""Close the browser."""
if self.driver:
self.driver.quit()
def navigate(self, url):
"""Navigate to URL and wait for load."""
self.driver.get(url)
WebDriverWait(self.driver, 15).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
def detect_captcha(self):
"""Detect which CAPTCHA type is on the page."""
source = self.driver.page_source
if re.search(r'data-sitekey=["\'][A-Za-z0-9_-]{40}["\']', source):
if "recaptcha/api.js" in source or "grecaptcha" in source:
return "recaptcha_v2"
if "cf-turnstile" in source or "challenges.cloudflare.com/turnstile" in source:
return "turnstile"
if re.search(r'recaptcha.*v3|render=[A-Za-z0-9_-]{40}', source):
return "recaptcha_v3"
captcha_imgs = self.driver.find_elements(
By.CSS_SELECTOR, "img.captcha, img[alt*='captcha'], img[src*='captcha']"
)
if captcha_imgs:
return "image"
return None
def solve_and_submit(self, url, form_data=None):
"""Navigate, solve CAPTCHA, fill form, and submit."""
self.navigate(url)
captcha_type = self.detect_captcha()
if not captcha_type:
print("No CAPTCHA detected")
return self._fill_and_submit(form_data)
print(f"Detected: {captcha_type}")
if captcha_type == "recaptcha_v2":
self._solve_recaptcha_v2()
elif captcha_type == "turnstile":
self._solve_turnstile()
elif captcha_type == "image":
self._solve_image()
return self._fill_and_submit(form_data)
def _solve_recaptcha_v2(self):
source = self.driver.page_source
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', source)
sitekey = match.group(1)
token = self._api_solve("userrecaptcha", googlekey=sitekey, pageurl=self.driver.current_url)
self.driver.execute_script(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
""")
def _solve_turnstile(self):
source = self.driver.page_source
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', source)
sitekey = match.group(1)
token = self._api_solve("turnstile", sitekey=sitekey, pageurl=self.driver.current_url)
self.driver.execute_script(f"""
document.querySelectorAll('[name="cf-turnstile-response"]')
.forEach(function(el) {{ el.value = '{token}'; }});
""")
def _solve_image(self):
img = self.driver.find_element(
By.CSS_SELECTOR, "img.captcha, img[alt*='captcha'], img[src*='captcha']"
)
answer = self._api_solve("base64", body=img.screenshot_as_base64)
captcha_input = self.driver.find_element(
By.CSS_SELECTOR, "input[name='captcha'], input[name='code']"
)
captcha_input.clear()
captcha_input.send_keys(answer)
def _fill_and_submit(self, form_data):
if form_data:
for name, value in form_data.items():
try:
field = self.driver.find_element(By.NAME, name)
field.clear()
field.send_keys(value)
except Exception:
pass
submit = self.driver.find_element(
By.CSS_SELECTOR, "button[type='submit'], input[type='submit']"
)
submit.click()
time.sleep(3)
return self.driver.current_url
def _api_solve(self, method, **params):
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key, "method": method, "json": 1, **params,
}, timeout=30)
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get", "id": task_id, "json": 1,
}, timeout=30).json()
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Solve timed out")
# Usage
solver = SeleniumCaptchaSolver(API_KEY)
solver.start()
try:
result_url = solver.solve_and_submit(
"https://example.com/login",
form_data={"username": "user@example.com", "password": "pass123"},
)
print(f"Result: {result_url}")
finally:
solver.stop()
Fehlerbehebung
| Symptom | Ursache | Lösung |
|---|---|---|
| CAPTCHA erkannt, aber die Token-Injektion schlägt fehl | Feld g-recaptcha-response nicht gefunden |
reCAPTCHA steckt oft in einem Iframe – dort zuerst hineinwechseln |
| Token eingefügt, aber das Formular wird nicht abgesendet | Callback nicht ausgelöst | Die reCAPTCHA-Callback-Funktion explizit aufrufen |
| Website meldet „webdriver erkannt“ | Automatisierungs-Flags nicht gesetzt | --disable-blink-features=AutomationControlled ergänzen |
| Screenshot des Bild-CAPTCHAs bleibt leer | Element nicht im sichtbaren Bereich | Element vor dem Screenshot in den Sichtbereich scrollen |
| Turnstile-Token wird abgelehnt | Falscher Sitekey | Sitekey erneut aus der Live-Seitenquelle extrahieren |
Häufige Fragen
Welche CAPTCHA-Typen deckt dieses Selenium-Setup ab?
reCAPTCHA v2 und v3, Cloudflare Turnstile sowie klassische Bild- und Text-CAPTCHAs. Alle laufen über dieselbe solve_captcha-Hilfsfunktion – es ändert sich nur der method-Parameter. hCaptcha und FunCaptcha werden von CaptchaAI nicht unterstützt.
Wie viele CAPTCHAs kann ich mit CaptchaAI gleichzeitig lösen?
So viele, wie Ihr Tarif Threads bietet. CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung. BASIC (15 $/Monat) umfasst 5 Threads, ADVANCE (90 $/Monat) 50 Threads – jeweils mit unbegrenzten Lösungen pro Thread. Für parallele Selenium-Worker starten Sie also so viele gleichzeitige Solves, wie Threads verfügbar sind.
Warum wird mein Token nach dem Einfügen nicht akzeptiert?
Meist fehlt der Callback. Bei reCAPTCHA v2 reicht es nicht, nur g-recaptcha-response zu setzen – viele Seiten warten auf die Callback-Funktion, bevor das Formular absendbar wird. Rufen Sie sie explizit auf. Bei Turnstile ist die häufigste Ursache ein falsch extrahierter Sitekey.
Kann ich Selenium im Headless-Modus betreiben?
Ja. Nutzen Sie --headless=new für die beste Kompatibilität. Die Lösung selbst erfolgt auf den Servern von CaptchaAI, daher wirkt sich der Headless-Modus nicht auf die CAPTCHA-Lösung aus.
Wann lohnt sich Selenium gegenüber reinen HTTP-Requests?
Immer dann, wenn die Seite JavaScript ausführt, Inhalte dynamisch nachlädt oder mehrstufige Abläufe hat. Für einfache, API-nahe Formularübermittlungen, bei denen Sie nur das Token brauchen, ist requests schneller – Selenium kostet 3–5 Sekunden Zusatzaufwand pro Seitenaufruf.
Fazit
Python Selenium und CaptchaAI decken zusammen jeden gängigen CAPTCHA-Fall in der Browser-Automatisierung ab: Typ aus der Seitenquelle erkennen, über die CaptchaAI-API lösen, das Token per JavaScript einfügen und das Formular absenden. Die Klasse SeleniumCaptchaSolver bündelt diesen Ablauf – von der Erkennung bis zum Absenden – in einem wiederverwendbaren Baustein.