Use Cases

Manipulação de CAPTCHA para automação de pesquisa de registros públicos

Precisa automatizar consultas em um tribunal, cartório ou junta comercial e travou no primeiro CAPTCHA? Na maioria dos casos a explicação é simples: esses portais rodam sistemas legados que nunca migraram para reCAPTCHA ou Turnstile — o desafio ainda é o CAPTCHA de imagem e OCR clássico, com texto distorcido, conta matemática ou desenho customizado. A vantagem: resolve-se com reconhecimento de texto puro, sem tokens JavaScript. Veja como identificar o desafio por portal e resolvê-lo em Python e JavaScript.

CAPTCHA em portais de registros públicos: o que esperar por categoria

Categoria do portal CAPTCHA típico Exemplo de desafio
Consulta processual (tribunais) Texto customizado Alfanumérico distorcido, 5–6 caracteres
Registro de imóveis / avaliação CAPTCHA matemático "Quanto é 4 + 7?"
Consulta de CNPJ / empresas Texto em imagem Letras distorcidas com ruído
Registros vitais reCAPTCHA v2 Seleção de grade de imagens
Alvarás e licenças municipais Texto simples Código numérico de 4 dígitos
Registros de gravames (UCC, EUA) OCR customizado Letras maiúsculas com ruído de fundo

Exemplos no Brasil e em Portugal

No Brasil, esse padrão é comum em sistemas judiciais estaduais, juntas comerciais e cartórios que ainda não digitalizaram a consulta; em Portugal, aparece em parte do registo predial e comercial. Ao automatizar, revise os termos de uso e considere a LGPD/RGPD se houver dados pessoais.

Buscando registros com o CAPTCHA resolvido automaticamente (Python)

O fluxo é sempre o mesmo: carregar a busca, localizar a imagem, resolver e submeter o formulário. A classe abaixo cobre os três passos, já tratando o portal sem CAPTCHA:

import requests
import base64
import time
from urllib.parse import urljoin

class PublicRecordsSearcher:
    def __init__(self, api_key):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })

    def search_court_records(self, portal_url, case_number):
        """Search court records, solving image CAPTCHAs as needed."""
        # Load the search page
        page = self.session.get(f"{portal_url}/search")

        # Extract CAPTCHA image
        captcha_img_url = self._extract_captcha_url(page.text, portal_url)
        if not captcha_img_url:
            # No CAPTCHA on this page
            return self._submit_search(portal_url, case_number)

        # Download and solve CAPTCHA
        img_response = self.session.get(captcha_img_url)
        captcha_text = self._solve_image_captcha(img_response.content)

        # Submit search with solved CAPTCHA
        return self._submit_search(portal_url, case_number, captcha_text)

    def _extract_captcha_url(self, html, base_url):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")

        # Look for common CAPTCHA image patterns
        captcha_img = (
            soup.find("img", {"id": "captchaImage"}) or
            soup.find("img", {"class": "captcha"}) or
            soup.find("img", attrs={"src": lambda s: s and "captcha" in s.lower()})
        )

        if captcha_img and captcha_img.get("src"):
            return urljoin(base_url, captcha_img["src"])
        return None

    def _solve_image_captcha(self, image_bytes):
        img_base64 = base64.b64encode(image_bytes).decode("utf-8")

        resp = requests.post("https://ocr.captchaai.com/in.php", data={
            "key": self.api_key,
            "method": "base64",
            "body": img_base64,
            "json": 1
        })
        task_id = resp.json()["request"]

        for _ in range(30):
            time.sleep(3)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1
            })
            data = result.json()
            if data["status"] == 1:
                return data["request"]

        raise TimeoutError("CAPTCHA solve timed out")

    def _submit_search(self, portal_url, case_number, captcha_text=None):
        form_data = {"caseNumber": case_number}
        if captcha_text:
            form_data["captcha"] = captcha_text

        response = self.session.post(
            f"{portal_url}/search/results",
            data=form_data
        )
        return response.text

# Usage
searcher = PublicRecordsSearcher("YOUR_API_KEY")
results = searcher.search_court_records(
    "https://courts.example.gov",
    "2024-CV-12345"
)

Erros comuns e como corrigir

Antes de estender a classe para outros tipos de desafio, vale fechar as pontas soltas mais comuns nessa implementação:

Problema Causa provável Como corrigir
Imagem retorna 403 Cookie de sessão ausente Carregue a busca primeiro, depois a imagem
Resposta errada com frequência Imagem de baixa qualidade Pré-processe (contraste, ruído) — veja o guia de pré-processamento
CAPTCHA muda a cada envio Token do formulário expirou Extraia os campos ocultos junto com a imagem
Busca retorna vazia POST perdeu cookies no redirecionamento Use allow_redirects=True e mantenha a sessão

Parâmetros que fazem diferença em portais governamentais

Com a implementação básica estável, estes são os parâmetros que mudam o comportamento do OCR — o próximo exemplo usa textinstructions diretamente:

Parâmetro Valor Quando usar
method base64 Imagem já baixada como bytes
method post Enviar o arquivo de imagem diretamente
language 0 CAPTCHAs de texto em português/latino
numeric 1 CAPTCHAs somente com dígitos
min_len / max_len Varia Quando a contagem de caracteres é previsível
textinstructions Instrução personalizada CAPTCHAs matemáticos ou formatos específicos

CAPTCHA matemático: mesma API, instrução diferente

Contas simples como "4 + 7 = ?" passam pela mesma API — a diferença é textinstructions, que orienta o OCR a resolver a equação em vez de só transcrever os caracteres:

def solve_math_captcha(self, image_bytes):
    """Solve math CAPTCHAs like '4 + 7 = ?'"""
    img_base64 = base64.b64encode(image_bytes).decode("utf-8")

    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": self.api_key,
        "method": "base64",
        "body": img_base64,
        "textinstructions": "solve the math equation and return only the number",
        "json": 1
    })
    task_id = resp.json()["request"]

    # Poll for result
    for _ in range(30):
        time.sleep(3)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": self.api_key,
            "action": "get",
            "id": task_id,
            "json": 1
        })
        data = result.json()
        if data["status"] == 1:
            return data["request"]

    raise TimeoutError("Math CAPTCHA solve timed out")

Buscando em vários portais na mesma execução (JavaScript)

Para cruzar o nome de uma empresa em vários estados, isole a lógica por portal e trate falhas sem derrubar a execução inteira:

class RecordsAggregator {
  constructor(apiKey) {
    this.apiKey = apiKey;
  }

  async searchAcrossPortals(query, portals) {
    const results = [];

    for (const portal of portals) {
      try {
        const data = await this.searchPortal(portal, query);
        results.push({ portal: portal.name, records: data });
      } catch (error) {
        results.push({ portal: portal.name, error: error.message });
      }
    }

    return results;
  }

  async searchPortal(portal, query) {
    const pageResponse = await fetch(portal.searchUrl);
    const html = await pageResponse.text();

    // Check for image CAPTCHA
    const captchaMatch = html.match(/captcha[^"]*\.(?:png|jpg|gif)/i);
    let captchaAnswer = null;

    if (captchaMatch) {
      const imgUrl = new URL(captchaMatch[0], portal.searchUrl).href;
      const imgData = await fetch(imgUrl);
      const buffer = await imgData.arrayBuffer();
      const base64 = Buffer.from(buffer).toString('base64');

      captchaAnswer = await this.solveImageCaptcha(base64);
    }

    // Submit search
    const formData = new URLSearchParams({ q: query });
    if (captchaAnswer) formData.append('captcha', captchaAnswer);

    const response = await fetch(portal.searchUrl, {
      method: 'POST',
      body: formData
    });

    return response.text();
  }

  async solveImageCaptcha(base64Image) {
    const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
      method: 'POST',
      body: new URLSearchParams({
        key: this.apiKey,
        method: 'base64',
        body: base64Image,
        json: '1'
      })
    });

    const { request: taskId } = await submitResp.json();

    for (let i = 0; i < 30; i++) {
      await new Promise(r => setTimeout(r, 3000));
      const result = await fetch(
        `https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
      );
      const data = await result.json();
      if (data.status === 1) return data.request;
    }

    throw new Error('CAPTCHA solve timed out');
  }
}

// Usage
const aggregator = new RecordsAggregator('YOUR_API_KEY');
const results = await aggregator.searchAcrossPortals('Smith LLC', [
  { name: 'State Business Registry', searchUrl: 'https://sos.example.gov/search' },
  { name: 'County Court Records', searchUrl: 'https://courts.example.gov/search' }
]);

Perguntas frequentes

Preciso de autorização para automatizar consultas em tribunais e cartórios?

Depende do portal e do volume. A consulta processual costuma ser pública por lei, mas dados pessoais coletados podem estar sujeitos à LGPD. Trate a coleta como QA autorizado, com os termos de uso revisados.

Qual plano da CaptchaAI faz sentido para monitorar vários portais estaduais em paralelo?

Depende de quantas consultas simultâneas você roda, não do volume mensal — os planos cobram por thread, com solves ilimitados. Para 5–10 portais em paralelo, o BASIC (US$ 15/mês, 5 threads) atende; em picos maiores, o STANDARD (US$ 30/mês, 15 threads) dá margem.

Por que tribunais e cartórios ainda usam CAPTCHA de texto distorcido em vez de reCAPTCHA?

Porque a maioria roda software legado, anterior ao reCAPTCHA e ao Turnstile. CAPTCHA customizado era o padrão quando esses portais foram construídos, e a TI pública atualiza devagar.

Qual a precisão da CaptchaAI para OCR de CAPTCHA distorcido nesses sistemas legados?

A CaptchaAI cobre mais de 27.500 variações de CAPTCHA de imagem com alta precisão. Para texto muito distorcido, textinstructions ajuda o OCR — por exemplo, "somente letras e números, sem espaços".

Como lidar com um CAPTCHA que muda toda vez que o formulário é reenviado?

Normalmente é o token oculto expirando antes da submissão. Extraia os campos ocultos (token CSRF, viewstate) junto com a imagem do CAPTCHA, na mesma requisição.

Comece agora

Depois de mapear o CAPTCHA do seu portal, crie sua conta e gere sua chave de API na CaptchaAI e resolva os desafios reais do fluxo.


Leia também

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