Der Unterschied ist drastisch: Sequenziell schaffen Sie mit reCAPTCHA v2 rund 240 Lösungen pro Stunde, parallel liegen 10.000 und mehr drin – bei identischen Kosten pro Lösung. Der Preis dafür ist Komplexität. Sequenzielles Lösen bedeutet ein CAPTCHA nach dem anderen: wenig Code, klarer Ablauf, leicht zu debuggen. Paralleles Lösen bedeutet viele Abfragen gleichzeitig, dafür mehr Sorgfalt bei Fehlern, Timing und Nebenläufigkeit. Dieser Vergleich zeigt, wo die Grenze zwischen beiden Ansätzen verläuft, wie viel Durchsatz Sie mit CaptchaAI realistisch erreichen und welcher Plan zu welcher Nebenläufigkeit passt.
Kurzentscheidung: sequenziell oder parallel?
- Sequenziell, wenn Sie unter 500 Lösungen pro Tag verarbeiten, Formulare einzeln abarbeiten, die Reihenfolge der Ergebnisse strikt einhalten müssen oder gerade entwickeln und debuggen.
- Parallel, wenn Sie über 500 Lösungen pro Tag brauchen, hohen Durchsatz priorisieren und bereit sind, Fehler pro Aufgabe zu isolieren sowie Nebenläufigkeit sauber zu begrenzen.
Alles dazwischen deckt der hybride Ansatz weiter unten ab. Die Kosten pro Lösung spielen bei der Entscheidung übrigens keine Rolle: CaptchaAI rechnet pro Thread ab, jeder Thread löst unbegrenzt viele CAPTCHAs im Abrechnungsmonat – nicht pro einzelner Abfrage.
Sequenzielles CAPTCHA-Lösen: einfach und nachvollziehbar
Ein CAPTCHA nach dem anderen: absenden → warten → abfragen → Ergebnis abrufen → weiter. Der Ablauf ist linear und damit gut nachvollziehbar – ideal für die Entwicklung.
# sequential_solver.py
import os
import time
import requests
API_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")
def solve_sequential(tasks):
"""Solve CAPTCHAs one by one."""
results = []
session = requests.Session()
for task in tasks:
# Submit
resp = session.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": task["sitekey"],
"pageurl": task["pageurl"],
"json": "1",
})
result = resp.json()
if result.get("status") != 1:
results.append({"error": result.get("request")})
continue
task_id = result["request"]
time.sleep(15)
# Poll
token = None
for _ in range(25):
poll = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get",
"id": task_id, "json": "1",
})
poll_result = poll.json()
if poll_result.get("status") == 1:
token = poll_result["request"]
break
if poll_result.get("request") != "CAPCHA_NOT_READY":
break
time.sleep(5)
results.append({"token": token} if token else {"error": "timeout"})
return results
# 10 tasks sequentially → ~150 seconds total
tasks = [{"sitekey": "SITEKEY", "pageurl": "https://example.com"}] * 10
start = time.time()
results = solve_sequential(tasks)
print(f"Completed in {time.time() - start:.0f}s")
Sequenziell spielt seine Stärken in diesen Fällen aus:
- Einseitige Workflows – ein Formular nach dem anderen ausfüllen
- Entwicklung und Debugging – ein klarer, gut nachvollziehbarer Ausführungsfluss
- Geringes Volumen – unter 500 Lösungen/Tag rechtfertigen den Mehraufwand der Parallelität nicht
- Reihenfolgeabhängige Abläufe – wenn die Ergebnisse zwingend nacheinander weiterverarbeitet werden
Paralleles CAPTCHA-Lösen mit asyncio
Beim parallelen Ansatz übermitteln Sie alle CAPTCHAs auf einmal und fragen die Ergebnisse gleichzeitig ab. Ein Semaphore begrenzt dabei die Zahl der gleichzeitig laufenden Anfragen – setzen Sie den Wert nie höher als die Threads, die Ihr Plan bereitstellt, sonst laufen Sie in ERROR_NO_SLOT_AVAILABLE.
# parallel_solver.py
import os
import asyncio
import aiohttp
API_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")
async def solve_one(session, sitekey, pageurl, semaphore):
"""Solve a single CAPTCHA within concurrency limits."""
async with semaphore:
# Submit
async with session.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY, "method": "userrecaptcha",
"googlekey": sitekey, "pageurl": pageurl, "json": "1",
}) as resp:
result = await resp.json(content_type=None)
if result.get("status") != 1:
return {"error": result.get("request")}
task_id = result["request"]
await asyncio.sleep(15)
# Poll
for _ in range(25):
async with session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get",
"id": task_id, "json": "1",
}) as resp:
poll_result = await resp.json(content_type=None)
if poll_result.get("status") == 1:
return {"token": poll_result["request"]}
if poll_result.get("request") != "CAPCHA_NOT_READY":
return {"error": poll_result.get("request")}
await asyncio.sleep(5)
return {"error": "timeout"}
async def solve_parallel(tasks, max_concurrent=50):
"""Solve CAPTCHAs in parallel with concurrency control."""
semaphore = asyncio.Semaphore(max_concurrent)
connector = aiohttp.TCPConnector(limit=max_concurrent)
async with aiohttp.ClientSession(connector=connector) as session:
coros = [
solve_one(session, t["sitekey"], t["pageurl"], semaphore)
for t in tasks
]
return await asyncio.gather(*coros)
# 10 tasks in parallel → ~20 seconds total
import time
tasks = [{"sitekey": "SITEKEY", "pageurl": "https://example.com"}] * 10
start = time.time()
results = asyncio.run(solve_parallel(tasks))
print(f"Completed in {time.time() - start:.0f}s")
Dasselbe Muster funktioniert in Node.js mit Promise.all und einem HTTPS-Agent mit begrenzter Socket-Zahl:
// parallel_solver.js
const axios = require('axios');
const https = require('https');
const API_KEY = process.env.CAPTCHAAI_KEY || 'YOUR_API_KEY';
const agent = new https.Agent({ keepAlive: true, maxSockets: 50 });
const api = axios.create({ baseURL: 'https://ocr.captchaai.com', httpsAgent: agent });
async function solveOne(sitekey, pageurl) {
const submit = await api.get('/in.php', {
params: { key: API_KEY, method: 'userrecaptcha', googlekey: sitekey, pageurl, json: '1' },
});
if (submit.data.status !== 1) return { error: submit.data.request };
await new Promise(r => setTimeout(r, 15000));
for (let i = 0; i < 25; i++) {
const poll = await api.get('/res.php', {
params: { key: API_KEY, action: 'get', id: submit.data.request, json: '1' },
});
if (poll.data.status === 1) return { token: poll.data.request };
if (poll.data.request !== 'CAPCHA_NOT_READY') return { error: poll.data.request };
await new Promise(r => setTimeout(r, 5000));
}
return { error: 'timeout' };
}
(async () => {
const tasks = Array.from({ length: 10 }, () => ({
sitekey: 'SITEKEY', pageurl: 'https://example.com',
}));
const start = Date.now();
const results = await Promise.all(tasks.map(t => solveOne(t.sitekey, t.pageurl)));
console.log(`Completed in ${((Date.now() - start) / 1000).toFixed(0)}s`);
console.log(`Solved: ${results.filter(r => r.token).length}/${tasks.length}`);
agent.destroy();
})();
Durchsatz nach Nebenläufigkeit – und der passende Plan
| Nebenläufige Lösungen | Geschätzter Durchsatz/Stunde | Speicher (Python) | Komplexität |
|---|---|---|---|
| 1 (sequenziell) | 240 | 30 MB | Gering |
| 10 | 2.400 | 50 MB | Gering |
| 25 | 6.000 | 80 MB | Mittel |
| 50 | 10.000+ | 120 MB | Mittel |
| 100 | 18.000+ | 200 MB | Hoch |
Basierend auf reCAPTCHA v2 mit einer mittleren Lösungszeit von 15 Sekunden.
Hinweis: Die Benchmarks und Vergleichswerte in diesem Artikel basieren auf internen Messungen und können je nach Region, Traffic-Muster und CAPTCHA-Konfiguration variieren. Eigene Tests mit realen Workflows sollten die maßgebliche Grundlage für Entscheidungen sein.
Threads richtig dimensionieren: welcher Plan passt?
Entscheidend ist der Zusammenhang zwischen Nebenläufigkeit und Threads: Ein Thread ist bei CaptchaAI genau ein CAPTCHA, das gerade in Bearbeitung ist. Wer 50 Lösungen gleichzeitig laufen lassen will, braucht also mindestens 50 Threads. Als DACH-Beispiel: Ein Scraping-Team betreibt seine Worker auf einem Hetzner-Server und möchte rund 10.000 reCAPTCHA v2 pro Stunde verarbeiten – das erfordert etwa 50 nebenläufige Threads. Als Orientierung für die Plan-Wahl (Preise in US-Dollar):
- < 500 Lösungen/Tag (sequenziell): BASIC (15 $/Monat, 5 Threads) oder STANDARD (30 $/Monat, 15 Threads)
- ~10.000/Stunde (≈ 50 nebenläufig): ADVANCE (90 $/Monat, 50 Threads)
- 100 nebenläufige Lösungen: PREMIUM (170 $/Monat, 100 Threads)
Hybrider Ansatz: sequenzieller Workflow, paralleles Lösen
Oft ist die beste Lösung eine Mischung: Der Workflow läuft geordnet ab, nur das eigentliche CAPTCHA-Lösen bündeln Sie in einem parallelen Batch.
# Process 10 URLs sequentially, but solve their CAPTCHAs in a parallel batch
urls = get_next_batch() # 10 URLs
captcha_params = [extract_sitekey(url) for url in urls] # Sequential extraction
tokens = asyncio.run(solve_parallel(captcha_params, max_concurrent=10)) # Parallel solving
for url, result in zip(urls, tokens):
submit_form(url, result.get("token")) # Sequential submission
So extrahieren Sie die Sitekeys geordnet, lösen alle CAPTCHAs gleichzeitig und senden die Formulare wieder in fester Reihenfolge ab – der Durchsatzgewinn steckt genau im mittleren Schritt.
Sequenziell vs. parallel: Vergleich auf einen Blick
| Faktor | Sequenziell | Parallel |
|---|---|---|
| Durchsatz (reCAPTCHA v2, Median 15 s) | ~240/Stunde | ~10.000+/Stunde |
| Code-Komplexität | Gering | Mittel bis hoch |
| Fehlerbehandlung | Unkompliziert | Fehler pro Aufgabe isolieren |
| Speicherbedarf | Minimal (~30 MB) | Skaliert mit der Nebenläufigkeit (~100–500 MB) |
| API-Kosten pro Lösung | Identisch | Identisch |
| Debugging | Einfach | Schwieriger (Race Conditions, Timing) |
| Reihenfolge der Ergebnisse | Bleibt erhalten | Nur mit explizitem Tracking |
| Geeignet für | < 500 Lösungen/Tag | > 500 Lösungen/Tag |
Kurz gesagt: Sequenziell gewinnt bei Einfachheit und Nachvollziehbarkeit, parallel bei Durchsatz – die Kosten pro Lösung bleiben in beiden Fällen gleich.
Fehlerbehebung
| Problem | Ursache | Lösung |
|---|---|---|
| Parallel langsamer als erwartet | Semaphore zu restriktiv gesetzt |
max_concurrent erhöhen – im Rahmen Ihrer verfügbaren Threads |
| Zufällige Fehler nur im Parallelbetrieb | Gemeinsam genutzter Zustand wird überschrieben | Zustand pro Coroutine bzw. Promise isolieren |
ERROR_NO_SLOT_AVAILABLE |
Mehr gleichzeitige Übermittlungen als Threads im Plan | max_concurrent senken oder Thread-Anzahl erhöhen |
| Ergebnisse in falscher Reihenfolge | fire-and-forget statt gather / allSettled |
Index-Tracking oder asyncio.gather bzw. Promise.allSettled nutzen |
Häufige Fragen
Wie viele Threads brauche ich für 10.000 Lösungen pro Stunde?
Bei einer mittleren Lösungszeit von 15 Sekunden schafft ein Thread rund 240 Lösungen pro Stunde. Für 10.000 pro Stunde benötigen Sie also etwa 45–50 nebenläufige Threads – abgedeckt durch den Plan ADVANCE (90 $/Monat, 50 Threads).
Bleibt die Reihenfolge der Ergebnisse beim parallelen Lösen erhalten?
Ja, sofern Sie asyncio.gather (Python) oder Promise.all bzw. Promise.allSettled (JavaScript) verwenden – diese liefern die Ergebnisse in der Reihenfolge der Eingabe zurück. Nur bei losem fire-and-forget geht die Reihenfolge verloren; dann hilft explizites Index-Tracking.
Was bedeutet der Fehler ERROR_NO_SLOT_AVAILABLE?
Er zeigt an, dass Sie mehr CAPTCHAs gleichzeitig übermitteln, als Ihr Plan Threads bereitstellt. Senken Sie max_concurrent auf die Zahl Ihrer Threads oder wechseln Sie in einen Plan mit mehr Threads.
Kostet paralleles Lösen mehr als sequenzielles?
Pro Lösung nicht – die Abrechnung erfolgt pro Thread mit unbegrenzten Lösungen je Thread, nicht pro Abfrage. Höhere Nebenläufigkeit setzt allerdings mehr Threads voraus, und mehr Threads bedeuten eine höhere Plan-Stufe. Sie zahlen also nicht pro Lösung mehr, sondern für die Kapazität, viele Lösungen gleichzeitig laufen zu lassen.
Wie viel Arbeitsspeicher braucht paralleles Lösen?
Sequenziell genügen rund 30 MB. Der Bedarf steigt mit der Nebenläufigkeit: etwa 120 MB bei 50 gleichzeitigen Lösungen und rund 200 MB bei 100. Für die meisten Setups bleibt das gut auf einem einzelnen kleinen Worker beherrschbar.
Verwandte Leitfäden
- Mehrere Aufgaben im Batch lösen
- CAPTCHA-Parallelität mit dem Python-ThreadPool
- Batch-Lösung in Node.js mit Promise.allSettled