Menos de 500 CAPTCHAs por dia? Resolva um de cada vez — é mais simples de depurar e não exige controle de concorrência.
Acima disso, resolver em paralelo reduz o tempo total de horas para minutos, ao custo de mais complexidade no código. Este guia compara as duas abordagens na prática com CaptchaAI: throughput, uso de memória, tratamento de erros e o ponto exato em que vale a pena migrar de uma para a outra.
Resposta rápida: qual modelo usar
- Menos de 500 CAPTCHAs por dia: resolução sequencial — código mais simples, depuração direta.
- Mais de 500 CAPTCHAs por dia: resolução paralela — o throughput sobe de ~240/hora para 10.000+/hora.
- Depurando um fluxo novo: comece sequencial e migre depois de validar a lógica de resolução.
- Pipeline de produção em alto volume: combine as duas — orquestração sequencial, resolução em lote paralelo (veja a abordagem híbrida mais abaixo).
Sequencial ou paralelo: comparação direta
| Fator | Sequencial | Paralelo |
|---|---|---|
| Throughput (reCAPTCHA v2, mediana de 15 s) | ~240/hora | ~10.000+/hora |
| Complexidade do código | Simples | Moderada a complexa |
| Tratamento de erros | Direto | Exige isolamento de erros concorrentes |
| Uso de memória | Mínimo (~30 MB) | Escala com a concorrência (~100–500 MB) |
| Custo de API por resolução | Igual | Igual |
| Dificuldade de depuração | Fácil | Mais difícil (condições de corrida, timing) |
| Ordem dos resultados | Preservada automaticamente | Exige rastreamento explícito |
| Indicado para | < 500 resoluções/dia | > 500 resoluções/dia |
Throughput por nível de concorrência
| Resoluções simultâneas | Throughput estimado/hora | Memória (Python) | Complexidade |
|---|---|---|---|
| 1 (sequencial) | 240 | 30 MB | Baixa |
| 10 | 2.400 | 50 MB | Baixa |
| 25 | 6.000 | 80 MB | Média |
| 50 | Mais de 10.000 | 120 MB | Média |
| 100 | 18.000+ | 200 MB | Alta |
Baseado em reCAPTCHA v2 com tempo médio de resolução de 15 s.
Se os seus workers rodam na região sa-east-1 (São Paulo) da AWS para reduzir a distância até seus usuários, vale lembrar: o tempo de resolução do CAPTCHA continua sendo o maior componente do total, não a latência de rede até o endpoint. A proximidade geográfica ajuda no RTT de cada requisição, mas o gargalo real é a concorrência disponível no seu plano — por isso a tabela acima é o ponto de partida certo para dimensionar max_concurrent, não a região do servidor.
Como funciona a resolução sequencial
Um CAPTCHA de cada vez: envia → aguarda → consulta o resultado → segue para o próximo. É o modelo mais fácil de ler em log e o que menos surpreende durante uma depuração.
# 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")
Quando vale a pena usar resolução sequencial
- Fluxos de página única — preenchendo um formulário por vez
- Depuração e desenvolvimento — fluxo de execução claro, fácil de acompanhar em log
- Volume baixo — menos de 500 resoluções/dia não justifica a complexidade do paralelismo
- Tarefas dependentes de ordem — quando o resultado de uma resolução precisa ser usado antes da próxima
Como funciona a resolução paralela
Envie todos os CAPTCHAs de uma vez e consulte os resultados simultaneamente — o ganho de tempo vem de sobrepor a espera de várias resoluções em vez de somá-las uma a uma:
# 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")
O parâmetro max_concurrent está diretamente ligado às threads do seu plano CaptchaAI: rodar max_concurrent=50 faz sentido em um plano ADVANCE (US$ 90/mês, 50 threads); ir além disso sem subir de plano só enfileira requisições que aguardam um slot livre.
Exemplo em JavaScript
// 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();
})();
Abordagem híbrida: sequencial no fluxo, paralelo na resolução
Use sequencial para orquestrar o fluxo de trabalho e paralelo apenas para a resolução do CAPTCHA:
# 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
Problemas comuns ao rodar em paralelo
| Problema | Causa | Correção |
|---|---|---|
| Paralelo mais lento que o esperado | Semáforo (semaphore) restritivo demais |
Aumente max_concurrent |
| Falhas aleatórias em paralelo | Estado compartilhado corrompido | Isole o estado por corrotina/promise |
| Resultados fora de ordem | asyncio.gather preserva a ordem de entrada |
Use rastreamento por índice, se precisar |
API retorna ERROR_NO_SLOT_AVAILABLE |
Envios simultâneos além do limite de threads do plano | Adicione um pequeno atraso entre os envios |
Ao investigar falhas intermitentes, é comum logar pageurl, sitekey e o resultado de cada resolução para comparar execuções. Se essas URLs carregam dados pessoais de usuários, trate esse log conforme a LGPD (ou o RGPD, para tráfego europeu): defina um período de retenção curto e evite manter esses registros além do necessário para depurar o problema.
Perguntas frequentes
Quantas threads eu preciso para rodar resolução em paralelo?
Depende do max_concurrent que você quer sustentar. O plano BASIC (US$ 15/mês, 5 threads) já permite testar o modelo paralelo em pequena escala; para os exemplos deste guia com max_concurrent=50, o plano ADVANCE (US$ 90/mês, 50 threads) é o ponto de partida — cada thread do plano corresponde a uma resolução em andamento.
A resolução em paralelo custa mais caro que a sequencial?
Não. A CaptchaAI cobra por thread, com resoluções ilimitadas por thread — não por requisição simultânea além do seu plano. O custo de API é o mesmo nos dois modelos; a diferença é o tempo total até terminar o lote.
Preciso reescrever todo o meu código para migrar de sequencial para paralelo?
Não, se a lógica de resolução já estiver isolada em uma função própria. A mudança fica restrita a envolver as chamadas em asyncio.gather (Python) ou Promise.all (JavaScript) — o resto do fluxo pode continuar igual.
Como evito resultados fora de ordem quando resolvo em paralelo?
asyncio.gather e Promise.all já preservam a ordem da lista de entrada nos resultados retornados. Se você despachar tarefas por conta própria (sem essas funções), associe cada resolução ao seu índice ou identificador original antes de enviar, e use isso para remontar a ordem depois.
Vale a pena combinar sequencial e paralelo no mesmo pipeline?
Sim, é o padrão mais comum em produção: orquestrar o fluxo (buscar URLs, extrair sitekeys, submeter formulários) de forma sequencial, e isolar só a resolução do CAPTCHA em um lote paralelo. Isso evita reescrever a orquestração inteira só para ganhar velocidade na parte que realmente é o gargalo.
Qual estratégia escolher agora
Escolha o modelo pelo seu volume diário — obtenha sua chave de API da CaptchaAI e teste as duas abordagens no seu próprio ambiente antes de decidir.
Guias relacionados: