Resolver o CAPTCHA de um site chinês depende de dois ajustes: enviar a imagem com language=2, para que o OCR leia ideogramas em vez de letras latinas, e tratar o GeeTest v3 como um desafio de parâmetros (gt e challenge), não como um arrastar de mouse. O resto é igual a qualquer integração com a API da CaptchaAI: envie a tarefa para in.php, consulte res.php e aplique o valor no formulário.
Na prática, o que quebra quase nunca é a resolução em si: é o encoding errado, o cookie de sessão que não acompanha a imagem baixada e o TTL curto do challenge.
Tipos de CAPTCHA que aparecem em sites chineses
O método da API depende do widget, e a distribuição aqui é bem diferente da de portais brasileiros:
| Tipo de CAPTCHA | Onde costuma aparecer | Método na CaptchaAI |
|---|---|---|
| Imagem com caracteres chineses | Portais públicos, bases acadêmicas | Imagem/OCR com language=2 |
| Operação aritmética em mandarim | Formulários de cadastro | Imagem/OCR |
| Quebra-cabeça deslizante GeeTest v3 | Baidu, Bilibili e outras plataformas grandes | GeeTest v3 |
| Clique nos caracteres em ordem | Instrução em chinês sobre a imagem | Imagem/OCR (coordenadas) |
| reCAPTCHA v2 | Versões internacionais de sites chineses | reCAPTCHA v2 |
Escopo, para evitar retrabalho: a CaptchaAI cobre o GeeTest v3; o v4 aparece apenas como "em breve", e hCaptcha e FunCaptcha (Arkose Labs) não estão entre os tipos atendidos.
Como identificar o desafio antes de escrever código
Cinco minutos no inspetor do navegador economizam horas de integração errada:
- Imagem simples: uma tag
<img>que muda a cada carregamento, com um campo de texto ao lado. - GeeTest v3: um script do fornecedor e uma requisição inicial devolvem
gt(fixo por site) echallenge(novo a cada sessão). - Clique nos caracteres: a instrução em chinês pede uma ordem; o retorno vem como coordenadas.
- reCAPTCHA v2: o widget é o mesmo do resto do mundo e preenche
g-recaptcha-response.
Python: OCR de caracteres chineses e GeeTest v3
As imagens costumam trazer instruções como 请输入验证码 ("digite o código de verificação"), e é o language=2 que faz o reconhecimento funcionar. O exemplo tem três funções: resolver a imagem de um arquivo local, baixá-la dentro da mesma sessão HTTP — o que preserva o cookie — e enviar um desafio GeeTest v3.
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",
)
A consulta ao res.php roda a cada 5 segundos, e a primeira já costuma trazer o resultado: menos de 0,5 s em imagens e menos de 12 s no GeeTest v3. A resposta do GeeTest vem com challenge, validate e seccode — os três seguem no envio do formulário.
O mesmo fluxo em Node.js
Se o coletor já roda em Node.js, a tradução é direta: URLSearchParams, fetch e o mesmo par in.php / res.php. Mantenha um teto de tentativas por tarefa — 24 para imagem, 36 para GeeTest.
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}`);
Encoding, sessão e rede: onde a integração falha
| Situação | O que fazer |
|---|---|
| Caracteres voltam ilegíveis | Force UTF-8 na requisição e na leitura da resposta |
| O site exige cookie de sessão | Baixe a imagem na mesma sessão que envia o formulário |
| Parâmetros do GeeTest no JavaScript | Extraia gt e challenge da página ou do endpoint que os gera |
| Limite de requisições nas CDNs da região | Reduza a cadência e use backoff exponencial |
| A imagem muda a cada carregamento | Baixe uma vez, resolva e envie; recarregar invalida o desafio |
Cenário: monitoramento autorizado de catálogo
Uma equipe de e-commerce em Curitiba confere toda semana fichas técnicas de fornecedores em portais aos quais já tem acesso contratado: cerca de 400 páginas por rodada, com CAPTCHA de caracteres chineses na primeira visita da sessão. Do Brasil, o RTT até a Ásia custa algumas centenas de milissegundos por requisição, e rodar os workers em sa-east-1 não encurta essa distância: o ganho vem de paralelizar. Com o plano BASIC (US$ 15/mês, 5 threads), cinco desafios seguem em paralelo e a rodada termina em bem menos de uma hora; a cobrança é por thread concorrente, com resoluções ilimitadas no mês. Se o catálogo dobrar, o passo natural é o STANDARD (US$ 30/mês, 15 threads).
Se a coleta envolver dados pessoais, as obrigações da LGPD — ou do RGPD, em Portugal — valem mesmo para dados vindos de fora do país: colete só o que o contrato autoriza.
Solução de problemas
| Sintoma | Causa provável | Correção |
|---|---|---|
| Texto resolvido com caracteres trocados | Encoding incompatível | Decodifique a resposta como UTF-8 de ponta a ponta |
challenge do GeeTest recusado |
O valor tem TTL curto | Envie logo após o carregamento; nunca reaproveite |
| O OCR devolve letras latinas | Mistura de escrita chinesa e latina | Envie language=2 para forçar o reconhecimento de ideogramas |
| O formulário rejeita a resposta correta | Cookies não mantidos | Use a mesma sessão para baixar a imagem e enviar |
| Taxa de resolução baixa em portais públicos | Ideogramas em traços densos | Capture em resolução maior |
Perguntas frequentes
O GeeTest v4 já está disponível?
Não. O v4 é descrito como "em breve" e ainda não pode ser resolvido pela API; em produção está o GeeTest v3, pelo método geetest. hCaptcha e FunCaptcha (Arkose Labs) também não são atendidos.
Preciso de um navegador headless para resolver esses desafios?
Não para o CAPTCHA em si: o envio e a consulta são requisições HTTP comuns. O navegador só entra se a página exigir JavaScript para gerar o challenge — e muitos sites expõem esse par em um endpoint que você pode chamar direto.
O OCR reconhece chinês simplificado e tradicional?
Sim. O solucionador de imagem trata as duas escritas (简体 e 繁體) com o mesmo language=2. A biblioteca cobre mais de 27.500 variantes de CAPTCHA de imagem, sem cobrança extra por tipo.
Como sei se o widget deslizante é mesmo GeeTest v3?
Procure o par de parâmetros: o GeeTest v3 expõe um gt fixo por site e um challenge que muda a cada sessão. Sem esse par, é provável que seja um controle proprietário, e o método geetest não se aplica.
Quanto custa manter uma coleta com CAPTCHAs chineses?
O custo acompanha a concorrência, não o número de desafios. Os planos são por thread, com resoluções ilimitadas no mês: BASIC (US$ 15/mês, 5 threads) atende rotinas pequenas; ADVANCE (US$ 90/mês, 50 threads) sustenta um pipeline contínuo.
Artigos relacionados
- Como resolver o callback do reCAPTCHA v2 pela API
- Resolver CAPTCHAs em Ruby com a API da CaptchaAI
- Resolver CAPTCHAs em Scala com a API da CaptchaAI
Próximas etapas
Pegue sua chave de API da CaptchaAI, rode o exemplo em Python contra uma imagem salva e só depois conecte o coletor.
Guias relacionados: