API Tutorials

Estratégias de resolução de CAPTCHA de imagem com vários caracteres

Um CAPTCHA de imagem com letras coladas, fonte diferente por caractere ou ruído de fundo derruba a precisão de qualquer OCR genérico. Isso não precisa derrubar sua automação: a API de imagem/OCR da CaptchaAI já lida com a maioria dessas distorções nativamente.

O trabalho do seu lado é descrever o desafio certo com os hints certos (textinstructions, regsense, minLen/maxLen). Este guia mostra como montar a chamada em Python, classificar o tipo de complexidade e o que fazer quando o mesmo CAPTCHA continua falhando.


Enviando o CAPTCHA pela API

O envio começa sempre da mesma forma, não importa a complexidade: a imagem em base64 vai para o endpoint de OCR, com hints opcionais no payload. A função abaixo é a base reutilizada por todas as estratégias das próximas seções.

import requests
import base64
import time
import os

API_KEY = os.environ["CAPTCHAAI_API_KEY"]


def solve_complex_image(image_b64, hints=None):
    """Solve a complex multi-character image CAPTCHA."""
    payload = {
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "json": 1,
    }

    if hints:
        payload.update(hints)

    resp = requests.post(
        "https://ocr.captchaai.com/in.php",
        data=payload,
        timeout=30,
    )
    result = resp.json()

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

    task_id = result["request"]

    time.sleep(8)
    for _ in range(24):
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }, timeout=15)
        data = resp.json()
        if data.get("status") == 1:
            return data["request"]
        if data["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(data["request"])
        time.sleep(5)

    raise TimeoutError("Solve timeout")

Como identificar o tipo de complexidade

O mesmo endpoint resolve todos os casos abaixo, mas o hint certo muda a taxa de acerto já na primeira tentativa. Comece classificando o desafio antes de montar os hints.

Casos simples e médios

  • Texto limpo — sem distorção, fonte uniforme; geralmente não precisa de hints extras.
  • Texto distorcido — letras giradas ou redimensionadas individualmente; use minLen/maxLen para restringir o tamanho esperado.
  • Ruído + linhas — ruído de fundo e linhas tachadas; descreva o ruído em textinstructions.
  • Variação de cor — cores diferentes por caractere; normalmente resolve sem hints adicionais.
  • Expressão matemática — números e operadores com resultado esperado; ative calc=1 para receber o valor já calculado em vez da expressão bruta.

Casos difíceis

  • Letras conectadas — os caracteres se sobrepõem ou se tocam.
  • Multi-fonte — cada caractere usa uma fonte diferente.

Os dois casos difíceis usam a mesma função base de envio — só muda o textinstructions enviado no payload, como mostram as duas estratégias a seguir.


Letras conectadas: o desafio mais comum para OCR

Letras conectadas ou sobrepostas são onde um OCR genérico erra primeiro — mas não para a CaptchaAI. Basta descrever o padrão no textinstructions e limitar a faixa de tamanho esperada da resposta:

def solve_connected_letters(image_path):
    """Solve CAPTCHA with connected/overlapping characters."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "textinstructions": "Characters may be connected or overlapping",
        "minLen": 4,
        "maxLen": 8,
    })

Ruído de fundo e caixa mista

Quando o CAPTCHA mistura maiúsculas e minúsculas sobre um fundo com ruído, ative regsense para preservar o caso e descreva o ruído no hint:

def solve_noisy_mixed(image_path):
    """Solve CAPTCHA with background noise and mixed case."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "regsense": 1,         # Case-sensitive
        "language": 2,         # Latin characters
        "textinstructions": "Ignore background lines and noise",
    })

CAPTCHA com várias fontes por caractere

Formulários que trocam a fonte a cada caractere tentam quebrar o reconhecimento por padrão visual. Avise sobre isso e restrinja o intervalo de tamanho esperado:

def solve_multi_font(image_path):
    """Solve CAPTCHA using multiple fonts per character."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "textinstructions": "Each character may use a different font or style",
        "minLen": 5,
        "maxLen": 7,
    })

Pré-processamento: quando vale a pena

Pré-processar antes de enviar não é obrigatório — a CaptchaAI já lida com a maior parte das distorções nativamente. Vale testar quando a imagem tem contraste baixo ou ruído pesado: o exemplo abaixo converte para tons de cinza, aumenta o contraste e binariza antes de codificar em base64.

# preprocess.py
from PIL import Image, ImageFilter, ImageEnhance
import io
import base64


def preprocess_for_ocr(image_path):
    """Preprocess image to improve OCR accuracy."""
    img = Image.open(image_path)

    # Convert to grayscale
    img = img.convert("L")

    # Increase contrast
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(2.0)

    # Sharpen
    img = img.filter(ImageFilter.SHARPEN)

    # Binarize (threshold)
    threshold = 128
    img = img.point(lambda p: 255 if p > threshold else 0)

    # Encode back to base64
    buffer = io.BytesIO()
    img.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode("ascii")

Repetindo o envio com relatório de erros

Se a primeira tentativa vier com resultado ruim, tente de novo com hints mais permissivos antes de desistir — e reporte a resposta incorreta para ajudar a CaptchaAI a ajustar o modelo para o seu tipo de CAPTCHA:

# retry_strategy.py


def solve_with_retry(image_b64, hints, max_retries=3):
    """Retry solving with fallback strategies."""
    strategies = [
        hints,                                          # Original hints
        {**hints, "textinstructions": ""},              # Without instructions
        {**hints, "numeric": 0, "regsense": 0},        # Relaxed constraints
    ]

    for i, strategy in enumerate(strategies[:max_retries]):
        try:
            result = solve_complex_image(image_b64, strategy)
            return {"text": result, "strategy": i, "success": True}
        except RuntimeError:
            continue

    return {"text": None, "strategy": -1, "success": False}


def report_bad_answer(task_id):
    """Report incorrect answer for quality feedback."""
    requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "reportbad",
        "id": task_id,
    }, timeout=10)

Perguntas frequentes

Preciso pré-processar as imagens antes de enviar para a CaptchaAI?

Só se estiver tendo resultados ruins. A CaptchaAI lida com a maioria das distorções nativamente, e o pré-processamento só ajuda mesmo em imagens com muito ruído ou contraste baixo.

O que significa "CAPCHA_NOT_READY" na resposta da consulta?

É o status intermediário enquanto o desafio ainda está sendo processado. O polling deve continuar consultando res.php normalmente nesse caso, e só tratar como erro se vier um texto diferente disso.

O CaptchaAI resolve CAPTCHAs de imagem com expressões matemáticas?

Sim. Ative calc=1 no envio para que o resultado volte já calculado, em vez da expressão bruta como "7 + 3".

Quantas threads preciso para resolver um lote grande de CAPTCHAs de imagem?

Depende do paralelismo, não do volume total — cada plano cobra por thread simultânea, com resolução ilimitada por thread. O BASIC (5 threads) cobre a maioria das suítes de QA; picos de execução paralela pedem STANDARD (15 threads) ou ADVANCE (50 threads).

Um mesmo tipo de CAPTCHA continua falhando na minha automação — o que fazer?

Reporte as respostas erradas com reportbad para ajudar a ajustar a precisão, e adicione um textinstructions mais específico descrevendo a característica do CAPTCHA (letras coladas, fonte trocada, ruído).


Onde isso aparece no dia a dia de QA

Um cenário comum de QA autorizado:

  • Uma equipe testa o formulário de cadastro em staging.example.com com CAPTCHAs de imagem gerados só para o ambiente de teste.
  • Os workers de resolução rodam na região sa-east-1 da AWS para manter a latência baixa a partir do Brasil.
  • Os CAPTCHAs de teste usam apenas dados fictícios — nunca capturas de tela de usuários reais — evitando problema de conformidade com a LGPD nos logs de execução.
  • Para esse volume, o plano BASIC (US$ 15/mês, 5 threads) costuma bastar; suítes maiores, com dezenas de CAPTCHAs em paralelo, sobem para STANDARD (US$ 30/mês, 15 threads) ou ADVANCE (US$ 90/mês, 50 threads).

Erros comuns e como corrigir

Sintomas rápidos para diagnosticar o problema:

  • Caracteres ausentes — letras conectadas mal interpretadas → adicione textinstructions sobre texto conectado.
  • Caracteres extras — ruído interpretado como texto → faça o pré-processamento e remova o ruído antes do envio.
  • Caso errado — maiúsculas/minúsculas não preservadas → defina regsense=1.
  • Resultado matemático como expressão — faltando calc=1 → ative o modo de cálculo para CAPTCHAs matemáticos.
  • Erro constante em um site específico — fonte específica do site → reporte respostas ruins com reportbad para ajustar o modelo.

Guias relacionados

Para aprofundar:


Resolva CAPTCHAs de imagem complexos sem perder precisão — comece agora com a CaptchaAI.

Os comentários estão desativados para este artigo.