Ein Scraper läuft stabil – bis die Zielseite ein reCAPTCHA ausliefert, die Antwort kein HTML mehr enthält und die Pipeline steht. Hier scheitern die meisten Web-Scraping-Workflows. Der zuverlässige Weg führt nicht am CAPTCHA vorbei, sondern durch das Lösen der Abfrage: Ihr Scraper extrahiert den Site-Key, schickt ihn an die API von CaptchaAI, bekommt ein Token zurück und setzt den Request fort.
Dieser Leitfaden begleitet Sie durch drei Schritte:
- Erkennen, welchen CAPTCHA-Typ eine Seite einsetzt – reCAPTCHA v2/v3, Cloudflare Turnstile oder ein Bild-CAPTCHA.
- Lösen der Abfrage über die API von CaptchaAI: Site-Key übermitteln, Ergebnis abfragen, Token entgegennehmen.
- Einbauen der Logik als wiederverwendbare Funktion, die an jeder CAPTCHA-Wand greift.
Der Fokus liegt auf reinen HTTP-Requests, wie sie in produktiven Scrapern üblich sind.
Warum CAPTCHAs Scraper ausbremsen
Websites lösen CAPTCHAs anhand von Verhaltenssignalen aus. Weicht ein Request vom Muster eines echten Browsers ab, erscheint statt der Seite eine Abfrage:
| Signal | Auslöser |
|---|---|
| Anfragerate | Zu viele Anfragen von einer einzelnen IP |
| Fehlende Cookies | Keine Session- oder Präferenz-Cookies |
| Bot-typische Header | Accept-Language oder Referer fehlen |
| JavaScript-Verhalten | Keine JS-Ausführung oder erkannter Headless-Browser |
| IP-Reputation | Rechenzentrums- oder Proxy-IP als verdächtig markiert |
Ein typisches Beispiel: Ein Preisvergleichs-Scraper, dessen Worker in einem Rechenzentrum bei Hetzner oder netcup laufen, trifft nach wenigen hundert Anfragen auf Cloudflare Turnstile, weil die Rechenzentrums-IP als verdächtig gilt. Ab da muss der Scraper die Abfrage lösen, um fortzufahren.
HTTP-Request oder Headless-Browser?
Bevor Sie Code schreiben, wählen Sie den Ansatz. Für die meisten Scraper genügen reine HTTP-Requests; erst stark JavaScript-lastige Seiten mit dynamisch gerendertem Site-Key verlangen einen Headless-Browser.
| Ansatz | Geeignet für | Aufwand |
|---|---|---|
HTTP-Requests (requests, axios) |
Formular-Submits mit reCAPTCHA v2/v3 oder Turnstile | gering |
| Headless-Browser (Selenium, Puppeteer) | JS-gerenderte Inhalte, dynamische Site-Keys | höher |
Die folgenden Beispiele setzen auf reine HTTP-Requests. Für JS-lastige Seiten kombinieren Sie dieselbe Lösungslogik mit einem Headless-Browser – etwa über CAPTCHA-Handling in Selenium mit Python.
Voraussetzungen
Für die Beispiele benötigen Sie:
| Voraussetzung | Details |
|---|---|
| CaptchaAI-API-Schlüssel | Von captchaai.com |
| Python 3.7+ oder Node.js 16+ | Für die Codebeispiele |
requests / axios |
HTTP-Client-Bibliothek |
| URL der Zielseite | Die Seite, die das CAPTCHA ausliefert |
| CAPTCHA-Site-Key | Aus dem Seitenquelltext extrahiert |
Schritt 1: CAPTCHA-Typ bestimmen
Bestimmen Sie zuerst, welchen CAPTCHA-Typ die Seite einsetzt. Ein Blick in den Seitenquelltext genügt meist:
reCAPTCHA v2:
<div class="g-recaptcha" data-sitekey="6Le-wvkS..."></div>
reCAPTCHA v3:
<script src="https://www.google.com/recaptcha/api.js?render=6Le-wvkS..."></script>
Cloudflare Turnstile:
<div class="cf-turnstile" data-sitekey="0x4AAAAA..."></div>
Jeder Typ benötigt bei der Übermittlung an CaptchaAI einen anderen method-Parameter:
| CAPTCHA-Typ | method-Parameter |
|---|---|
| reCAPTCHA v2/v3 | userrecaptcha |
| Cloudflare Turnstile | turnstile |
| Cloudflare Challenge | cloudflare_challenge |
hCaptcha und FunCaptcha stehen bewusst nicht in der Tabelle: CaptchaAI unterstützt diese Typen derzeit nicht.
Schritt 2: Site-Key extrahieren
Steht der Typ fest, lesen Sie den Site-Key aus dem HTML.
Python (mit requests + BeautifulSoup)
from bs4 import BeautifulSoup
import requests
page = requests.get("https://example.com/protected-page", headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
soup = BeautifulSoup(page.text, "html.parser")
# reCAPTCHA v2
recaptcha_div = soup.find("div", class_="g-recaptcha")
if recaptcha_div:
site_key = recaptcha_div["data-sitekey"]
print(f"reCAPTCHA v2 site key: {site_key}")
Node.js (mit Cheerio)
const axios = require("axios");
const cheerio = require("cheerio");
const { data } = await axios.get("https://example.com/protected-page");
const $ = cheerio.load(data);
const siteKey = $(".g-recaptcha").attr("data-sitekey");
console.log("Site key:", siteKey);
Schritt 3: CAPTCHA an CaptchaAI übermitteln
Mit Site-Key und Seiten-URL übermitteln Sie die Aufgabe und fragen dann das Ergebnis ab, bis das Token vorliegt.
Hinweis zum Polling: Fragen Sie das Ergebnis im Abstand von etwa fünf Sekunden ab, statt in einer engen Schleife. So vermeiden Sie unnötige Anfragen, während CaptchaAI die Abfrage im Hintergrund löst.
Python
import requests
import time
API_KEY = "YOUR_API_KEY"
SITE_KEY = "6Le-wvkS..."
PAGE_URL = "https://example.com/protected-page"
# Submit
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": SITE_KEY,
"pageurl": PAGE_URL
})
if not resp.text.startswith("OK|"):
raise Exception(f"Submit error: {resp.text}")
task_id = resp.text.split("|")[1]
print(f"Task submitted: {task_id}")
# Poll for result
while True:
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
token = result.text.split("|")[1]
print(f"Solved! Token: {token[:50]}...")
break
raise Exception(f"Solve error: {result.text}")
Node.js
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
const SITE_KEY = "6Le-wvkS...";
const PAGE_URL = "https://example.com/protected-page";
// Submit
const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: SITE_KEY,
pageurl: PAGE_URL,
},
});
const taskId = submitResp.data.split("|")[1];
// Poll
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
while (true) {
await sleep(5000);
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId },
});
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data.startsWith("OK|")) {
const token = result.data.split("|")[1];
console.log("Token:", token.substring(0, 50));
break;
}
throw new Error(`Error: ${result.data}`);
}
Schritt 4: Token an die Zielseite senden
Sobald das Token vorliegt, senden Sie es mit den Formulardaten, die die Seite erwartet:
Feldname beachten: Das Token gehört in das Feld, das der CAPTCHA-Typ vorgibt – bei reCAPTCHA
g-recaptcha-response, bei Turnstilecf-turnstile-response. Passt der Feldname nicht, weist die Seite die Übermittlung ab.
Python
# Submit the solved token with the form
form_data = {
"g-recaptcha-response": token,
"username": "user@example.com",
"password": "password123"
}
response = requests.post(PAGE_URL, data=form_data, headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
print(f"Status: {response.status_code}")
Schritt 5: Wiederverwendbare Scraper-Funktion bauen
Kapseln Sie die Lösungslogik in eine wiederverwendbare Funktion, die Sie an jeder CAPTCHA-Wand aufrufen:
Timeout im Blick behalten: Die Schleife bricht nach 60 Versuchen im Abstand von fünf Sekunden ab – also nach rund fünf Minuten. Für Massen-Scraping passen Sie diese Obergrenze an Ihren Durchsatz an.
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_captcha(site_key, page_url, method="userrecaptcha"):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": method,
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
raise Exception(resp.text)
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError("CAPTCHA solve timed out")
# Use in your scraper
def scrape_page(url, site_key):
token = solve_captcha(site_key, url)
response = requests.post(url, data={"g-recaptcha-response": token})
return response.text
Praxistipps für stabiles Scraping
Diese Gewohnheiten senken, wie oft überhaupt ein CAPTCHA erscheint – lösen müssen Sie es nur noch im Rest der Fälle:
- User-Agents rotieren – Realistische Browser-User-Agent-Strings verwenden
- Verzögerungen einbauen – Anfragen im Abstand von 2–5 Sekunden verteilen, um Rate-Limiting zu vermeiden
- Proxys einsetzen – Residential-Proxys rotieren, um Anfragen zu verteilen
- Cookies pflegen – Session-Cookies über alle Anfragen hinweg beibehalten
- Token zwischenspeichern – Manche Token funktionieren im Gültigkeitsfenster für mehrere Anfragen
DSGVO-Hinweis: IP-Adressen und viele gescrapte Inhalte gelten in der EU als personenbezogene Daten. Prüfen Sie vor dem Sammeln Ihre Rechtsgrundlage und die Nutzungsbedingungen der Zielseite – das bleibt Ihre Sorgfaltspflicht.
Fehlerbehebung
Tritt trotzdem eine Abfrage auf und die Lösung schlägt fehl, hilft diese Tabelle bei den häufigsten Fehlern:
| Fehler | Ursache | Lösung |
|---|---|---|
ERROR_WRONG_USER_KEY |
Ungültiger API-Schlüssel | Schlüssel im Dashboard auf captchaai.com prüfen |
ERROR_ZERO_BALANCE |
Kein Guthaben | Guthaben im Konto aufladen |
ERROR_CAPTCHA_UNSOLVABLE |
Abfrage nicht lösbar | Site-Key und URL auf Korrektheit prüfen |
CAPCHA_NOT_READY (läuft endlos) |
Langsame Lösung oder falsche Parameter | Timeout erhöhen; prüfen, ob der Site-Key zur Seite passt |
| Token von der Seite abgelehnt | Token abgelaufen oder falscher Site-Key | Token innerhalb von 120 Sekunden verwenden; Site-Key bestätigen |
Fazit
Ein CAPTCHA muss keinen Scraper stoppen. Erkennen Sie den Typ, lösen Sie die Abfrage über die API von CaptchaAI und setzen Sie das Token in den Request ein – gekapselt in eine Funktion, die an jeder Wand greift. Kombiniert mit sauberen Headers, Residential-Proxys und moderater Anfragerate bleibt Ihre Pipeline auch auf geschützten Seiten stabil.
Häufige Fragen
Warum bekommt mein Scraper trotz Proxys weiterhin CAPTCHAs?
Meist an der IP-Reputation: Rechenzentrums- und günstige Proxy-IPs sind bei Anti-Bot-Diensten bekannt und werden früher geprüft. Residential-Proxys, saubere Header und Session-Cookies senken die Auslöserate spürbar – ganz ohne CAPTCHAs kommt aber kaum ein Scraper aus.
Muss ich für reCAPTCHA v3 etwas anderes tun als für v2?
Der Ablauf ist identisch. reCAPTCHA v3 liefert einen Score statt einer Checkbox, und der Site-Key steht im render-Parameter des Script-Tags (siehe Schritt 1). Übermittelt wird beides über method=userrecaptcha.
Löst CaptchaAI auch hCaptcha beim Scraping?
Nein. CaptchaAI unterstützt hCaptcha und FunCaptcha derzeit nicht. Abgedeckt sind reCAPTCHA v2/v3, Cloudflare Turnstile und Challenge sowie Bild- und Raster-CAPTCHAs. Für Turnstile nutzen Sie method=turnstile, für Challenge-Seiten method=cloudflare_challenge – siehe Cloudflare Turnstile per API lösen.
Kann ich mehrere CAPTCHAs parallel lösen?
Ja. Übermitteln Sie mehrere Aufgaben gleichzeitig und fragen Sie jedes Ergebnis separat ab; wie viele parallel laufen, bestimmt Ihre Thread-Anzahl. Mehr dazu: CAPTCHAs parallel statt sequenziell lösen.
Was kostet das CAPTCHA-Lösen bei großem Scraping-Volumen?
CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro gelöstem CAPTCHA – jeder Plan enthält unbegrenzte Lösungen. Sie wählen also einen Plan mit genug Threads für Ihren Durchsatz, etwa BASIC (15 $/Monat, 5 Threads) oder ADVANCE (90 $/Monat, 50 Threads).