Больше 500 запросов на решение CAPTCHA в сутки — и последовательная обработка станет узким местом. До этого порога хватает одного потока с CaptchaAI, после нужен параллелизм. Ниже — код на Python и JavaScript, таблица пропускной способности и типичные ошибки перехода.
Что выбрать: экспресс-чек-лист
Прежде чем читать код, определите объём и требования вашего пайплайна:
- До 500 решений в день — оставайтесь на последовательной модели, экономите на сложности и отладке.
- Больше 500 решений в день или пиковые нагрузки — переходите на параллельную обработку, throughput растёт на порядок.
- Результаты нужны строго по порядку — последовательная модель проще, даже при большом объёме.
- Несколько сайтов или клиентов одновременно — параллельная модель с пулом соединений экономит время ожидания.
Сравнение в одной таблице
| Фактор | Последовательно | Параллельно |
|---|---|---|
| Пропускная способность (reCAPTCHA v2) | ~240/час | ~10 000+/час |
| Сложность кода | Простая | Умеренная–высокая |
| Обработка ошибок | Простая | Нужна изоляция |
| Память | Минимальная (~30 МБ) | ~100–500 МБ |
| Стоимость API за решение | Такая же | Такая же |
| Отладка | Проще | Сложнее (гонки, тайминги) |
| Порядок результатов | Сохраняется | Нужно отслеживание |
| Оптимально для | < 500 решений/день | > 500 решений/день |
Дальше — на что каждая цифра влияет в реальном пайплайне: код, память и сценарии, где параллелизм окупается уже на первой неделе.
Пример: сколько потоков нужно агентству
Агентству нужно около 6 000 решений reCAPTCHA v2 в час для нескольких клиентов. Расчёт простой:
- 6 000 решений/час ÷ 240 (пропускная способность одного потока) ≈ 25 параллельных задач.
- По таблице выше это уровень ADVANCE ($90/мес, 50 потоков) — с запасом на пиковую нагрузку.
- Тарифы CaptchaAI в долларах, поэтому бюджет не «плавает» вместе с курсом, даже если счета выставляются в разных странах.
Последовательная обработка CAPTCHA
Как это устроено
По одной CAPTCHA за раз: отправка → ожидание → опрос → результат → следующая задача. Каждый шаг блокирует поток выполнения, пока не придёт ответ от res.php, поэтому суммарное время растёт линейно с числом задач.
# 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")
Когда стоит остаться на последовательной модели
- Одношаговые сценарии — одна форма за проход, дополнительная сложность не нужна.
- Отладка — линейный, предсказуемый ход выполнения проще воспроизвести по логам.
- Небольшой объём — до 500 решений в день параллелизм не окупается: выигрыш по времени меньше, чем расходы на изоляцию ошибок.
- Зависимость по порядку — следующий шаг требует результата предыдущего, гонки состояний тут ни к чему.
Совет: если объём растёт нерегулярно, переходите на параллельную модель заранее — не дожидайтесь первого затора в очереди.
Параллельная обработка CAPTCHA
Как это устроено
Все CAPTCHA уходят в API почти одновременно, результаты опрашиваются параллельно — семафор ограничивает число одновременных запросов, чтобы не упереться в 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")
Пример на JavaScript
Та же логика на Node.js, с ограничением пула соединений через maxSockets:
// 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();
})();
Совет: начинайте с
max_concurrent=10и увеличивайте постепенно, проверяя долю ошибокERROR_NO_SLOT_AVAILABLEна каждом шаге.
Пропускная способность по уровню параллелизма
| Параллельных решений | Пропускная способность/час | Память (Python) | Сложность |
|---|---|---|---|
| 1 (последовательно) | 240 | 30 МБ | Низкая |
| 10 | 2 400 | 50 МБ | Низкая |
| 25 | 6 000 | 80 МБ | Средняя |
| 50 | 10 000+ | 120 МБ | Средняя |
| 100 | 18 000+ | 200 МБ | Высокая |
Расчёт для reCAPTCHA v2 со средним временем решения 15 секунд. Для команд, которые размещают воркеры в европейских регионах или в Казахстане, задержка сети добавляет заметный процент к времени опроса — закладывайте это в расчёт max_concurrent.
Гибридная схема: последовательно и параллельно вместе
Рабочий процесс последовательный, а решение CAPTCHA уходит в параллельный батч. Такой шаблон удобен, когда остальная логика — переходы по страницам, заполнение форм — должна остаться предсказуемой, а узкое место именно в ожидании ответа CAPTCHA API:
# 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
Совет: в гибридной схеме держите таймаут опроса CAPTCHA короче, чем таймаут внешнего запроса, который его вызвал, — иначе зависшая задача решения заблокирует всю остальную последовательную логику.
Типичные проблемы и решения
Большинство сбоев при переходе на параллельную модель сводятся к четырём причинам:
| Проблема | Причина | Решение |
|---|---|---|
| Параллельный режим медленнее ожидаемого | Семафор выставлен слишком строго | Увеличьте max_concurrent |
| Случайные сбои в параллели | Общее состояние повреждается | Изолируйте состояние на сопрограмму/promise |
| Результаты не в том порядке | asyncio.gather сохраняет порядок |
Добавьте индекс при необходимости |
ERROR_NO_SLOT_AVAILABLE |
Слишком много одновременных отправок | Добавьте задержку между запросами |
Частые вопросы
Быстрые ответы на вопросы, которые чаще всего задают при переходе с одного потока на пул задач.
Сколько потоков нужно для перехода на параллельную обработку?
Ориентир — поток на 3–5 одновременных решений. 25 задач закрывает ADVANCE (50 потоков); для сотни и выше — CORPORATE ($240/мес, 150 потоков) или ENTERPRISE ($300/мес, 200 потоков).
Параллельная обработка стоит дороже последовательной?
Нет. Тарификация по потокам с неограниченным числом решений — цена та же, результат быстрее.
С какого объёма имеет смысл переходить на параллелизм?
Порог — около 500 решений в день. До него конкурентность выигрывает во времени, а не в деньгах.
Что делать при ERROR_NO_SLOT_AVAILABLE?
Отправки идут слишком плотно. Два быстрых исправления:
- Добавьте небольшую задержку между вызовами
in.php. - Снизьте
max_concurrentи увеличивайте его постепенно.
Что делать, если сеть нестабильна и часть запросов не проходит?
При нестабильном соединении добавьте повтор с экспоненциальной задержкой на уровне HTTP-клиента — сам API не меняет поведение при параллельных запросах, страдает только транспортный уровень между вашим воркером и ocr.captchaai.com.