Hintergründe

Umgang mit reCAPTCHA v2 in Web Scraping-Workflows

Ein Scraper, der auf reCAPTCHA v2 trifft, muss nicht scheitern: Sie leiten die Abfrage an eine Solver-API weiter und setzen den Lauf mit dem zurückgelieferten Token fort. Konkret sind es vier Schritte – den Sitekey aus dem HTML auslesen, ihn zusammen mit der Seiten-URL an CaptchaAI übermitteln, das gelöste Token abfragen und es wieder in die Seite einfügen. Kein Kontrollkästchen, kein Bildraster, keine manuelle Zwischenstufe.

Dieser Leitfaden zeigt den kompletten Ablauf mit lauffähigem Code – für Python (Selenium und requests) und für Node.js (Puppeteer), ergänzt um einen browserlosen HTTP-Weg für reine Formular-Flows.

Kurz gefasst: Sitekey auslesen → mit der Seiten-URL an CaptchaAI übermitteln → Token im Polling abfragen → in g-recaptcha-response einfügen oder an den Callback übergeben. Derselbe Ablauf trägt Selenium, Puppeteer und den reinen HTTP-Weg.


Wie der Ablauf im Detail funktioniert

Jedes reCAPTCHA-v2-Widget liefert zwei Werte, die Ihr Scraper an CaptchaAI weitergibt:

Parameter Bedeutung
googlekey öffentlicher Sitekey, fest im HTML der Seite verankert
pageurl Adresse, unter der das CAPTCHA erscheint

Ihr Scraper übermittelt beide an die API und fragt das Ergebnis anschließend im Polling ab. Das gelöste Token tragen Sie in das Feld g-recaptcha-response ein oder übergeben es an die hinterlegte Callback-Funktion. Das Backend der Zielseite prüft das Token gegen Google und gibt die Anfrage frei – die eigentliche Bilderkennung übernimmt CaptchaAI auf eigener Infrastruktur. Wichtig: Jedes Token ist nur wenige Minuten gültig, deshalb lösen Sie erst, wenn Sie es unmittelbar danach absenden.


Python: reCAPTCHA v2 mit Selenium lösen

Der folgende Ablauf öffnet die Seite mit Selenium, liest den Sitekey aus, übermittelt ihn an CaptchaAI, fragt das Token im Polling ab und fügt es zurück in die Seite ein:

import requests
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

# Step 1: Open the page with Selenium
driver = webdriver.Chrome()
driver.get("https://example.com/protected-page")

# Step 2: Extract the sitekey
sitekey = driver.find_element(By.CSS_SELECTOR, ".g-recaptcha").get_attribute("data-sitekey")
page_url = driver.current_url

# Step 3: Submit to CaptchaAI
response = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url,
    "json": 1
}).json()

task_id = response["request"]

# Step 4: Poll for result
token = None
for _ in range(40):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY",
        "action": "get",
        "id": task_id,
        "json": 1
    }).json()

    if result.get("status") == 1:
        token = result["request"]
        break
    if result.get("request") != "CAPCHA_NOT_READY":
        raise RuntimeError(f"Solve failed: {result['request']}")

# Step 5: Inject the token and submit
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").innerHTML = "{token}";'
)

# Check for callback
callback = driver.execute_script(
    'var el = document.querySelector(".g-recaptcha"); '
    'return el ? el.getAttribute("data-callback") : null;'
)
if callback:
    driver.execute_script(f'{callback}("{token}");')
else:
    driver.find_element(By.CSS_SELECTOR, "form").submit()

# Step 6: Scrape the data
print(driver.page_source[:500])
driver.quit()

Schritt 3 und 4 bilden das Kernmuster jeder Integration: erst übermitteln, dann in kurzen Abständen abfragen, bis status den Wert 1 liefert.

Node.js: reCAPTCHA v2 mit Puppeteer lösen

Dieselbe Logik in Node.js mit Puppeteer: Die Seite wird geladen, der Sitekey extrahiert und das Token nach dem Polling per page.evaluate eingefügt.

const puppeteer = require("puppeteer");

async function scrapeWithCaptcha(url) {
  const browser = await puppeteer.launch({ headless: "new" });
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: "networkidle2" });

  // Extract sitekey
  const sitekey = await page.$eval(".g-recaptcha", (el) => el.dataset.sitekey);

  // Submit to CaptchaAI
  const submitRes = await fetch(
    `https://ocr.captchaai.com/in.php?${new URLSearchParams({
      key: "YOUR_API_KEY",
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: url,
      json: 1,
    })}`
  );
  const { request: taskId } = await submitRes.json();

  // Poll for result
  let token;
  for (let i = 0; i < 40; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const res = await fetch(
      `https://ocr.captchaai.com/res.php?${new URLSearchParams({
        key: "YOUR_API_KEY",
        action: "get",
        id: taskId,
        json: 1,
      })}`
    );
    const data = await res.json();
    if (data.status === 1) {
      token = data.request;
      break;
    }
    if (data.request !== "CAPCHA_NOT_READY")
      throw new Error(`Solve failed: ${data.request}`);
  }

  // Inject token
  await page.evaluate((t) => {
    document.getElementById("g-recaptcha-response").innerHTML = t;
    const cb = document.querySelector(".g-recaptcha")?.dataset.callback;
    if (cb && window[cb]) window[cb](t);
  }, token);

  // Wait for navigation after form submit
  await page.waitForNavigation({ waitUntil: "networkidle2" });
  const content = await page.content();
  await browser.close();
  return content;
}

scrapeWithCaptcha("https://example.com/protected-page").then(console.log);

Browser oder reiner HTTP-Weg?

Nicht jeder Scraper braucht einen echten Browser. Wenn die Zielseite das Feld g-recaptcha-response direkt in einer Formularübermittlung akzeptiert, genügt ein schlanker HTTP-Client. Die folgende Übersicht hilft bei der Entscheidung:

Kriterium Browser (Selenium/Puppeteer) Reiner HTTP-Weg
Ressourcenbedarf höher niedrig
JavaScript-Rendering ja nein
Callback-Aufruf möglich ja nur wenn ein POST-Feld genügt
Parallelisierung begrenzt einfach

Der reine HTTP-Weg lässt sich auf einem schlanken Worker – etwa einem kleinen Hetzner- oder netcup-Server – gut parallelisieren. Laden Sie die Seite zunächst über eine Session, damit die Cookies erhalten bleiben, und senden Sie das Token anschließend mit dem regulären POST-Body:

import requests
import time

session = requests.Session()
session.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0"

# Load the page to get cookies
session.get("https://example.com/protected-page")

# Solve the CAPTCHA
sitekey = "6Le-wvkSAAAAAN..."  # extracted from page HTML
solve_resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY", "method": "userrecaptcha",
    "googlekey": sitekey, "pageurl": "https://example.com/protected-page",
    "json": 1
}).json()

task_id = solve_resp["request"]
time.sleep(15)

# Poll
for _ in range(30):
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id, "json": 1
    }).json()
    if result.get("status") == 1:
        token = result["request"]
        break
    time.sleep(5)

# Submit with token
resp = session.post("https://example.com/protected-page", data={
    "g-recaptcha-response": token,
    "other_field": "value"
})
print(resp.text[:500])

Headless- oder Headed-Modus?

Manche Seiten weisen Headless-Browser ab, bevor das CAPTCHA überhaupt lädt. Damit Ihr Client als vollwertiger Browser auftritt, helfen diese Einstellungen:

  • headless: "new" in Puppeteer (der moderne Headless-Modus)
  • --disable-blink-features=AutomationControlled als Chromium-Flag
  • eine echte, aktuelle User-Agent-Zeichenkette
  • bei Bedarf Proxy-Rotation für die anschließenden Scraping-Anfragen

Bleibt eine Seite trotzdem hartnäckig, ist der sichtbare Headed-Modus oft die robustere Wahl – langsamer im Durchsatz, aber stabiler im Ergebnis.


Skalierung: Threads statt Stückzahl

Wer aus Deutschland, Österreich oder der Schweiz Daten extrahiert, sollte die rechtliche Seite mitdenken: IP-Adressen und personenbezogene Inhalte fallen unter die DSGVO. Prüfen Sie vor jedem Lauf die Rechtsgrundlage sowie die Nutzungsbedingungen und die robots.txt der Zielseite – das ist Sorgfaltspflicht des Betreibers, nicht Aufgabe des Solver-Dienstes.

Für den Durchsatz rechnet CaptchaAI pro Thread ab, nicht pro Lösung: Ein Thread ist eine gleichzeitig laufende Abfrage; sobald sie fertig ist, nimmt der Thread die nächste an. Innerhalb eines Tarifs sind die Lösungen pro Thread unbegrenzt – Sie planen also nach Parallelität, nicht nach Stückzahl.

Tarif Preis Threads
BASIC 15 $/Monat 5
STANDARD 30 $/Monat 15
ADVANCE 90 $/Monat 50

Preise verstehen sich in US-Dollar. Für einen einzelnen Scraper genügt oft BASIC; parallele Worker mit vielen gleichzeitigen Abfragen profitieren von ADVANCE aufwärts.


FAQ

Wie lange dauert eine reCAPTCHA-v2-Lösung?

Zwischen 15 und 60 Sekunden pro Abfrage. Wenn Sie in großem Umfang scrapen, lassen Sie mehrere Lösungen parallel laufen – über die Threads Ihres Tarifs.

Warum ruft die Seite nach dem Einfügen keine Aktion aus?

Viele reCAPTCHA-Widgets erwarten den Aufruf einer Callback-Funktion, nicht nur ein gefülltes g-recaptcha-response-Feld. So gehen Sie vor:

  • das Attribut data-callback auslesen
  • die Funktion mit dem Token aufrufen
  • fehlt der Callback: das Formular direkt absenden

Funktioniert der Ansatz auch bei reCAPTCHA v2 Invisible?

Ja. Die unsichtbare Variante nutzt denselben Sitekey und dieselbe API-Methode – Sie extrahieren den Sitekey identisch und fügen das Token wie gewohnt ein. Nur der sichtbare Klick entfällt.

Und wenn die Zielseite Enterprise reCAPTCHA nutzt?

Ergänzen Sie Ihre Anfrage um enterprise=1. Details dazu im Leitfaden reCAPTCHA v2 Enterprise per API lösen.


So starten Sie

  1. API-Schlüssel unter captchaai.com/api.php holen
  2. Sitekey von der Zielseite auslesen
  3. Mit den Codebeispielen oben lösen und einfügen
  4. Für hohe Volumen über parallele Threads skalieren

Weiterführende Anleitungen

Kommentare sind für diesen Artikel deaktiviert.