Troubleshooting

Imagem CAPTCHA retorna resposta errada: otimização de qualidade

Na grande maioria dos casos, uma resposta errada da CaptchaAI para um CAPTCHA de imagem não é falha do motor de OCR — é a imagem que chega ao endpoint cortada, comprimida demais ou codificada de forma incorreta antes mesmo de ser analisada. A boa notícia é que esse tipo de erro é fácil de isolar: em poucos minutos você identifica qual das cinco causas abaixo está no seu pipeline e aplica a correção certa, sem precisar trocar de fornecedor nem reescrever a lógica de automação.

Isso é especialmente comum em times que rodam workers de captura em regiões como sa-east-1 (São Paulo) e enviam screenshots via conexões instáveis: a imagem chega comprimida pelo próprio driver do navegador, e o sintoma parece "a CaptchaAI errou", quando na verdade o problema é o que foi enviado.

Dica rápida: antes de investigar código, abra a imagem que está sendo enviada — não a que aparece na tela do navegador. Se ela estiver cortada, borrada ou em branco, o problema está no lado do envio, não na resolução.


Causas mais comuns de resposta errada em CAPTCHA de imagem

As cinco causas abaixo respondem pela maioria dos casos abertos com esse sintoma, da mais para a menos frequente:

Causa Frequência Correção
Imagem cortada incorretamente Muito comum Capture o elemento CAPTCHA completo
Baixa resolução/compressão excessiva Comum Envie uma imagem de maior qualidade
Codificação de imagem errada Comum Verifique a codificação base64
Dica de idioma/tipo ausente Ocasional Adicione language ou textinstructions
Imagem desatualizada ou corrompida Ocasional Capture uma imagem nova antes de resolver

Checklist de diagnóstico rápido

Antes de aplicar qualquer correção, cruze o sintoma que você está vendo com a linha correspondente. Isso evita testar as seis correções abaixo uma por uma sem necessidade.

Sintoma Diagnóstico Correção
Resposta é uma sequência sem sentido Codificação base64 errada Verifique a codificação de ida e volta (round-trip)
Resposta é parecida, mas errada Baixa qualidade de imagem Pré-processe: aumente a escala, nitidez e contraste
Resposta tem número de caracteres errado Faltam dicas de comprimento Adicione os parâmetros min_len/max_len
Resposta mistura letras e dígitos Falta dica de tipo Adicione numeric=1 ou numeric=2
Resposta vazia retornada Imagem em branco ou corrompida Valide a imagem antes de enviar
Resposta correta, mas o site rejeita Sensibilidade a maiúsculas/minúsculas Adicione textinstructions sobre o caso

Correção 1: valide a qualidade da imagem antes de enviar

Antes de gastar uma chamada de API, rode uma checagem local rápida — resolução mínima, proporção de pixels em branco e tamanho do arquivo. Isso pega metade dos casos de resposta errada antes mesmo do envio.

import base64
from io import BytesIO
from PIL import Image


def validate_captcha_image(image_path):
    """Check image quality before submitting to CaptchaAI."""
    img = Image.open(image_path)
    width, height = img.size
    issues = []

    # Minimum resolution
    if width < 50 or height < 20:
        issues.append(f"Too small: {width}x{height}px (min 50x20)")

    # Check if mostly blank
    pixels = list(img.getdata())
    if img.mode == "RGB":
        white_count = sum(1 for p in pixels if p[0] > 250 and p[1] > 250 and p[2] > 250)
    else:
        white_count = sum(1 for p in pixels if p > 250)

    blank_ratio = white_count / len(pixels)
    if blank_ratio > 0.95:
        issues.append(f"Image appears blank ({blank_ratio:.0%} white)")

    # File size check
    img_bytes = BytesIO()
    img.save(img_bytes, format="PNG")
    size_kb = img_bytes.tell() / 1024
    if size_kb < 1:
        issues.append(f"File too small ({size_kb:.1f} KB) — may be empty")
    if size_kb > 600:
        issues.append(f"File too large ({size_kb:.0f} KB) — submit under 600 KB")

    return issues


issues = validate_captcha_image("captcha.png")
if issues:
    for issue in issues:
        print(f"WARNING: {issue}")
else:
    print("Image quality OK")

Rode essa checagem como um passo do próprio pipeline de envio, não como um script avulso — assim ela pega o problema antes de gastar uma chamada de API e antes de o erro chegar ao seu monitoramento como "taxa de acerto caindo".


Correção 2: corrija a codificação Base64

Esse é o erro mais silencioso da lista: o código roda sem exceção, mas o valor enviado não corresponde ao conteúdo real da imagem. É o que acontece quando alguém codifica o caminho do arquivo (uma string) em vez dos bytes da imagem.

import base64


def encode_captcha(image_path):
    """Properly encode a CAPTCHA image to base64."""
    with open(image_path, "rb") as f:
        raw = f.read()

    encoded = base64.b64encode(raw).decode("ascii")

    # Verify round-trip
    decoded = base64.b64decode(encoded)
    assert decoded == raw, "Base64 encoding corrupted the image"

    return encoded


# WRONG — encoding a file path string
bad = base64.b64encode(b"captcha.png").decode()  # Encodes filename, not image!

# CORRECT — encoding file contents
with open("captcha.png", "rb") as f:
    good = base64.b64encode(f.read()).decode()

Correção 3: pré-processe a imagem para melhorar o OCR

Pré-processamento não é obrigatório na maioria dos casos, mas resolve os casos-limite: imagem muito pequena, contraste baixo entre texto e fundo, ou bordas suaves demais para o OCR distinguir caracteres parecidos (por exemplo "0" e "O").

from PIL import Image, ImageFilter, ImageEnhance
from io import BytesIO
import base64


def preprocess_captcha(image_path):
    """Improve image quality for better OCR accuracy."""
    img = Image.open(image_path)

    # Convert to RGB if needed
    if img.mode != "RGB":
        img = img.convert("RGB")

    # Upscale small images
    width, height = img.size
    if width < 200:
        scale = 200 / width
        img = img.resize(
            (int(width * scale), int(height * scale)),
            Image.LANCZOS,
        )

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

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

    # Convert to PNG bytes
    buffer = BytesIO()
    img.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode()

Aplique esse pré-processamento como fallback — só quando a Correção 1 já sinalizou um problema de qualidade — em vez de rodar em toda imagem por padrão, para não gastar tempo de CPU sem necessidade.


Correção 4: adicione dicas de tipo e idioma

Quando você já sabe o formato esperado — só dígitos, comprimento fixo, alfabeto cirílico — informe isso na requisição. É a diferença entre o OCR "adivinhar" entre letras e números parecidos e já receber a resposta filtrada corretamente.

Parâmetros de dica mais usados

  • language: 0 padrão, 1 cirílico, 2 latino
  • numeric: 1 só dígitos, 2 só letras
  • min_len / max_len: comprimento esperado da resposta
  • textinstructions: instrução livre, útil para casos como sensibilidade a maiúsculas
import requests


def solve_image(api_key, image_base64, **hints):
    """Submit image CAPTCHA with quality hints."""
    data = {
        "key": api_key,
        "method": "base64",
        "body": image_base64,
        "json": 1,
    }

    # Add optional hints for better accuracy
    if "language" in hints:
        data["language"] = hints["language"]  # 0=default, 1=Cyrillic, 2=Latin
    if "textinstructions" in hints:
        data["textinstructions"] = hints["textinstructions"]
    if "numeric" in hints:
        data["numeric"] = hints["numeric"]  # 1=digits only, 2=letters only
    if "min_len" in hints:
        data["min_len"] = hints["min_len"]
    if "max_len" in hints:
        data["max_len"] = hints["max_len"]

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


# Example: Digits-only CAPTCHA, 4-6 characters
result = solve_image(
    "YOUR_API_KEY",
    encoded_image,
    numeric=1,
    min_len=4,
    max_len=6,
)

# Example: Case-sensitive text
result = solve_image(
    "YOUR_API_KEY",
    encoded_image,
    textinstructions="Case-sensitive, enter exactly as shown",
)

Correção 5: capture o elemento CAPTCHA completo, não a página inteira

Este é o item que mais aparece na tabela de causas acima. Um recorte manual de coordenadas fixas quebra assim que o layout da página muda um pixel; o screenshot do elemento pelo próprio driver resolve isso de forma estável.

from selenium import webdriver
from selenium.webdriver.common.by import By
import base64


def capture_captcha_element(driver, selector):
    """Screenshot only the CAPTCHA element, not the full page."""
    element = driver.find_element(By.CSS_SELECTOR, selector)

    # Element screenshot (better than page crop)
    png_bytes = element.screenshot_as_png

    # Verify it's not empty
    if len(png_bytes) < 500:
        raise ValueError("Screenshot too small — element may not be visible")

    return base64.b64encode(png_bytes).decode()


# Usage
driver = webdriver.Chrome()
driver.get("https://example.com")
image_b64 = capture_captcha_element(driver, "img#captchaImage")

Correção 6: trate CAPTCHAs dinâmicos ou rotativos

Alguns CAPTCHAs de imagem trocam a imagem periodicamente ou expiram em poucos segundos. Se você captura a imagem, espera, e só então envia, corre o risco de enviar uma imagem que já não corresponde ao desafio ativo na página — a resposta certa para a imagem antiga, mas errada para o desafio atual.

import time


def solve_with_fresh_image(driver, api_key, captcha_selector):
    """Capture and solve CAPTCHA immediately to avoid expiry."""
    # Wait for CAPTCHA to load fully
    time.sleep(2)

    # Capture fresh
    element = driver.find_element(By.CSS_SELECTOR, captcha_selector)
    png_bytes = element.screenshot_as_png
    body = base64.b64encode(png_bytes).decode()

    # Submit immediately
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "base64",
        "body": body,
        "json": 1,
    }, timeout=30)
    result = resp.json()

    if result.get("status") != 1:
        raise RuntimeError(result.get("request"))

    task_id = result["request"]

    # Poll — image CAPTCHAs solve fast
    time.sleep(5)
    for _ in range(12):
        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(3)

    raise TimeoutError("Image solve timeout")

Perguntas frequentes

Qual o tamanho mínimo de imagem aceito pela CaptchaAI?

O mínimo prático é 50x20 pixels, mas imagens muito próximas desse limite tendem a gerar mais erro. Se o CAPTCHA original já é pequeno, aplique o upscale da Correção 3 antes de enviar — o ganho de precisão costuma compensar o passo extra.

O print da página inteira em vez do elemento do CAPTCHA causa erro?

Sim, e é a causa mais frequente de resposta errada na prática. Um recorte manual por coordenadas fixas some do lugar certo assim que o layout muda um pixel; o screenshot do elemento (Correção 5) captura exatamente a área do desafio, independentemente de reflow na página.

Preciso pré-processar as imagens antes de enviar?

Só se a imagem original já vier com baixa qualidade. A CaptchaAI lida bem com CAPTCHAs de imagem padrão sem nenhum pré-processamento. Aumentar a escala de imagens muito pequenas e o contraste ajuda apenas em casos-limite.

Posso reportar uma resposta errada?

Sim. Use o endpoint reportbad com o ID da tarefa para reportar respostas incorretas. Isso ajuda a melhorar a precisão do OCR e pode gerar crédito na sua conta.


Guias relacionados


Resolva imagens com precisão — experimente a CaptchaAI.

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