Anwendungsfälle

CAPTCHAs in Web-Scraping-Workflows automatisch lösen

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 Turnstile cf-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:

  1. User-Agents rotieren – Realistische Browser-User-Agent-Strings verwenden
  2. Verzögerungen einbauen – Anfragen im Abstand von 2–5 Sekunden verteilen, um Rate-Limiting zu vermeiden
  3. Proxys einsetzen – Residential-Proxys rotieren, um Anfragen zu verteilen
  4. Cookies pflegen – Session-Cookies über alle Anfragen hinweg beibehalten
  5. 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).

Verwandte Leitfäden

Kommentare sind für diesen Artikel deaktiviert.