Anwendungsfälle

Lösen von CAPTCHAs auf chinesischen Websites mit CaptchaAI

Zwei Methoden decken den größten Teil dessen ab, was auf chinesischen Websites an CAPTCHA-Abfragen erscheint: Bild/OCR mit aktivierter Erkennung chinesischer Schriftzeichen und GeeTest v3. Exotische Solver braucht es selten – die Arbeit steckt in der Kodierung, in stabilen Sitzungen und in kurzlebigen challenge-Werten.

In DACH-Teams, die Listenpreise von B2B-Marktplätzen, Zolltarifnummern oder Treffer aus akademischen Datenbanken erheben, liegt die Fehlerursache deshalb fast nie bei der Abfrage selbst. Der Lauf bricht ab, weil das Bild in einer anderen Sitzung geladen wurde als das Formular oder weil zwischen Abruf und Übermittlung zu viele Sekunden vergingen. Dieser Leitfaden ordnet die Typen, zeigt Code für Python und Node.js und benennt die Betriebsdetails dahinter.

Welche CAPTCHA-Typen auf chinesischen Websites vorkommen

Die Verteilung unterscheidet sich von europäischen Seiten: reCAPTCHA erscheint vor allem auf international ausgerichteten Portalen, inländische Plattformen setzen eigene Bildabfragen und GeeTest ein.

CAPTCHA-Typ Typischer Einsatzort CaptchaAI-Methode
Bild-CAPTCHA mit chinesischen Schriftzeichen Behörden- und Regierungsportale, akademische Datenbanken Bild/OCR mit language=2
Rechenaufgabe in chinesischer Schrift Registrierungs- und Anmeldeformulare Bild/OCR
GeeTest v3 (Schiebepuzzle) Baidu, Bilibili, viele große Plattformen GeeTest v3
Schriftzeichen der Reihe nach anklicken Abfragen vom Typ 请按顺序点击 Bild/OCR im Koordinatenmodus
reCAPTCHA v2 international ausgerichtete chinesische Websites reCAPTCHA v2

Was CaptchaAI abdeckt – und was nicht

Vor der Planung einer Quelle lohnt der Abgleich mit der tatsächlichen Abdeckung:

  • Unterstützt: Bild/OCR inklusive chinesischer Zeichen, Rasterbild-CAPTCHA, GeeTest v3, reCAPTCHA v2/v3 samt Enterprise, Cloudflare Turnstile und Challenge, BLS.
  • Nur in der Beta: CaptchaFox (Beta), Friendly Captcha (Beta), Lemin (Beta).
  • GeeTest v4: nicht verfügbar, offiziell als „bald verfügbar“ angekündigt – planen Sie keine Quelle darauf.
  • hCaptcha und FunCaptcha (Arkose Labs): nicht im Leistungsumfang.
  • Tencent CAPTCHA: keine eigene Methode – prüfen Sie, ob die Seite eine Bildvariante als Rückfallebene anbietet.

Praxisbeispiel: Lieferantenpreise für ein Importteam in Nordrhein-Westfalen

Ein Beschaffungsteam im Maschinenbau verfolgt wöchentlich die Katalogpreise mehrerer chinesischer B2B-Marktplätze. Der Crawler läuft als nächtlicher GitLab-CI-Job auf einem Hetzner-Server; nach einigen hundert Abrufen schiebt die Quelle ein Bild-CAPTCHA mit chinesischen Schriftzeichen vor die Trefferliste.

Bewährt hat sich ein einziger durchgehender Ablauf: Der Job hält eine requests-Session offen, lädt das CAPTCHA-Bild über genau diese Sitzung, übergibt es an CaptchaAI, trägt die Antwort in das Formularfeld ein und sendet ab. Erst danach liest der Parser die Preistabelle aus. In die Betriebsdokumentation gehört außerdem die datenschutzrechtliche Bewertung: IP-Adressen gelten nach DSGVO als personenbezogene Daten, und Zweck, Rechtsgrundlage und Löschfristen sollten festgehalten sein.

Python: Bild-CAPTCHA und GeeTest v3 lösen

Chinesische Bild-CAPTCHAs zeigen meist eine Aufforderung wie 请输入验证码 („Bitte geben Sie den Bestätigungscode ein“). Entscheidend ist der Parameter language: 2 – er schaltet die Erkennung chinesischer Schriftzeichen frei. Ohne ihn deutet die OCR die Zeichen häufig als lateinische Buchstaben.

import requests
import base64
import time

API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


def solve_chinese_image_captcha(image_path: str) -> str:
    """Solve a Chinese character image CAPTCHA."""
    with open(image_path, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode()

    resp = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "language": 2,          # 2 = Chinese characters supported
        "json": 1,
    }, timeout=30).json()

    if resp.get("status") != 1:
        raise RuntimeError(f"Submit failed: {resp.get('request')}")

    task_id = resp["request"]
    start = time.monotonic()

    while time.monotonic() - start < 120:
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve failed: {poll.get('request')}")

    raise RuntimeError("Timeout")


def solve_chinese_captcha_from_url(captcha_url: str, cookies: dict = None) -> str:
    """Download and solve a Chinese CAPTCHA from a URL."""
    session = requests.Session()
    if cookies:
        session.cookies.update(cookies)

    resp = session.get(captcha_url, timeout=15)
    image_b64 = base64.b64encode(resp.content).decode()

    submit = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "language": 2,
        "json": 1,
    }, timeout=30).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit: {submit.get('request')}")

    task_id = submit["request"]
    for _ in range(24):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve: {poll.get('request')}")

    raise RuntimeError("Timeout")


# --- GeeTest on Chinese platforms ---

def solve_geetest_chinese(gt: str, challenge: str, pageurl: str) -> dict:
    """Solve GeeTest v3 commonly found on Baidu, Bilibili, etc."""
    resp = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "geetest",
        "gt": gt,
        "challenge": challenge,
        "pageurl": pageurl,
        "json": 1,
    }, timeout=30).json()

    if resp.get("status") != 1:
        raise RuntimeError(f"Submit: {resp.get('request')}")

    task_id = resp["request"]
    for _ in range(36):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            # GeeTest returns challenge, validate, seccode
            return poll["request"]
        raise RuntimeError(f"Solve: {poll.get('request')}")

    raise RuntimeError("Timeout")


# Usage — Chinese government portal
text = solve_chinese_image_captcha("chinese_captcha.png")
print(f"Chinese CAPTCHA text: {text}")

# GeeTest on a Chinese platform
geetest_result = solve_geetest_chinese(
    gt="b46d1900d0a894591f1561f8c35670a7",
    challenge="dynamic_challenge_string",
    pageurl="https://www.example.cn/login",
)

Die drei Funktionen decken die üblichen Fälle ab:

  • solve_chinese_image_captcha liest ein lokal gespeichertes Bild und liefert den erkannten Text.
  • solve_chinese_captcha_from_url lädt das Bild innerhalb einer bestehenden Sitzung – der Weg, den Sie fast immer brauchen, weil das Bild an das Sitzungscookie gebunden ist.
  • solve_geetest_chinese übermittelt gt und challenge und liefert challenge, validate und seccode zurück, die Sie mit dem Formular absenden.

Das Polling fragt im Abstand von fünf Sekunden ab und bricht kontrolliert ab: nach 120 Sekunden bei Bildabfragen, nach rund drei Minuten bei GeeTest.

Node.js: chinesische CAPTCHAs in JavaScript lösen

Auf Node.js bleibt der Ablauf identisch: dieselben Endpunkte, dieselben Parameter, fetch statt requests.

const API_KEY = "YOUR_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
const fs = require("fs");

async function solveChineseImageCaptcha(imagePath) {
  const imageB64 = fs.readFileSync(imagePath, "base64");

  const body = new URLSearchParams({
    key: API_KEY,
    method: "base64",
    body: imageB64,
    language: "2",
    json: "1",
  });

  const resp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
  if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);

  const taskId = resp.request;
  for (let i = 0; i < 24; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return poll.request;
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

async function solveGeeTest(gt, challenge, pageurl) {
  const body = new URLSearchParams({
    key: API_KEY,
    method: "geetest",
    gt,
    challenge,
    pageurl,
    json: "1",
  });

  const resp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
  if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);

  const taskId = resp.request;
  for (let i = 0; i < 36; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return poll.request;
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

// Usage
const text = await solveChineseImageCaptcha("chinese_captcha.png");
console.log(`Chinese text: ${text}`);

language wird hier als String "2" übergeben – URLSearchParams akzeptiert ausschließlich Strings.

Betriebspraxis: Kodierung, Sitzung, Proxys

Stolperstelle Vorgehen
Zeichen werden falsch dargestellt Kodierung durchgängig auf UTF-8 festlegen, in Anfrage wie Antwort
Bild ist an die Sitzung gebunden Bild in derselben Session laden, aus der das Formular abgesendet wird
gt und challenge stecken im Seitenskript Aus dem Seitenquelltext oder dem vorgelagerten API-Aufruf extrahieren
Rate-Limiting durch chinesische CDNs Anfragen entzerren und Proxys mit chinesischen IP-Adressen einsetzen
Abfrage erneuert sich bei jedem Laden Bild einmal laden, lösen, absenden – kein erneutes Laden dazwischen

Typische Fehlerbilder und ihre Ursache

Symptom Ursache Abhilfe
Ergebnis enthält Platzhalterzeichen statt Schriftzeichen Antwort wurde nicht als UTF-8 dekodiert Kodierung der Antwort explizit setzen
challenge wird abgelehnt Der Wert hat eine kurze Lebensdauer Extraktion, Lösung und Übermittlung in denselben Ablauf legen
Erkannter Text ist lateinisch statt chinesisch language fehlt oder steht auf dem Standardwert language: 2 mitschicken
Auffällig viele Abfragen in kurzer Zeit Abrufrate zu aggressiv für die Quelle Intervalle drosseln, Sitzungen stabil halten, Proxy-Qualität prüfen
Daten fehlen trotz gelöster Abfrage Der Parser liest eine veraltete Ansicht aus Erst nach Übernahme des Tokens in derselben Sitzung extrahieren
Kosten steigen stärker als geplant Wiederholungen lösen zusätzliche Abfragen aus Nur kritische Schritte lösen, Wiederholungen pro Quelle protokollieren

Kosten planen: Threads statt Einzelabrechnung

CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung. Innerhalb des Abrechnungsmonats sind die Lösungen pro Thread unbegrenzt, und es gibt keine Aufschläge nach CAPTCHA-Typ. Für die Planung zählt daher nicht die Gesamtzahl der Abfragen, sondern die Parallelität.

  • BASIC (15 $/Monat, 5 Threads) trägt einen einzelnen nächtlichen Lauf mit wenigen Quellen.
  • STANDARD (30 $/Monat, 15 Threads) passt zu mehreren parallelen Extraktionsjobs.
  • ADVANCE (90 $/Monat, 50 Threads) ist die Stufe für dauerhaft laufende Pipelines mit vielen Quellen.

Alle Preise verstehen sich in US-Dollar.

Häufige Fragen

Warum kommen die erkannten Schriftzeichen verstümmelt an?

Fast immer liegt es an der Dekodierung: Die Antwort wird nicht als UTF-8 gelesen. Setzen Sie das Encoding im HTTP-Client explizit und schreiben Sie auch Zwischenergebnisse UTF-8-kodiert weg. Erst danach lohnt der Blick auf die Bildqualität – gering aufgelöste Zeichenbilder senken die Trefferquote spürbar.

Wie lange ist ein GeeTest-challenge brauchbar?

Nur kurz. Der Wert wird pro Sitzung erzeugt und verliert schnell seine Gültigkeit. Extraktion, Lösung und Übermittlung gehören deshalb in einen zusammenhängenden Ablauf. Ein Skript, das gt und challenge morgens einsammelt und abends verwendet, wird abgelehnt.

Brauche ich Proxys mit chinesischer IP-Adresse?

Häufig ja. Viele Quellen prüfen die Herkunft der Anfrage und liefern aus Europa keine oder nur eingeschränkte Inhalte. Residential-Proxys mit chinesischen IP-Adressen erhöhen die Chance auf eine normale Antwort; wichtig ist, dass Bildabruf und Formularübermittlung über dieselbe Route laufen.

Was kostet ein Lauf mit 50.000 Abfragen im Monat?

Das hängt nicht an den 50.000 Abfragen, sondern an der Parallelität. Sie zahlen für gleichzeitig laufende Lösungen: Ein nächtlicher Batch mit moderater Nebenläufigkeit kommt mit STANDARD (30 $/Monat, 15 Threads) aus, dauerhaft laufende Pipelines eher mit ADVANCE (90 $/Monat, 50 Threads).

Was tun, wenn die Seite bei jedem Aufruf eine neue Abfrage erzeugt?

Laden Sie das Bild genau einmal, lösen Sie es und senden Sie das Formular ab, ohne die Seite zwischendurch neu zu laden. Jeder zusätzliche Aufruf erzeugt eine neue Abfrage und entwertet die vorherige Lösung – der häufigste Grund für Kosten ohne Gegenwert.


Verwandte Leitfäden

Kommentare sind für diesen Artikel deaktiviert.