Use Cases

Coleta de dados de saúde atrás das paredes do CAPTCHA

Diretório de prestador (NPI), portal de preço de medicamento e registro de ensaio clínico publicam dado que reguladores como o CMS querem em circulação; o CAPTCHA ali não existe para barrar essa pesquisa, existe para conter bot agressivo. O obstáculo real é técnico: reCAPTCHA v2, CAPTCHA de imagem e, em alguns portais de qualidade hospitalar, Cloudflare Turnstile aparecem antes de qualquer busca — e cada um pede uma resposta diferente do script. A API da CaptchaAI resolve esses desafios, então a busca segue sem intervenção manual, o que libera a equipe para focar na pergunta que importa de verdade: qual desse dado é seguro coletar.


Onde os CAPTCHAs aparecem em portais de saúde

O tipo de desafio muda conforme o portal e o dado que ele protege. Antes de escrever qualquer script, vale mapear qual CAPTCHA aparece em cada fonte:

Portal Tipo de CAPTCHA Dado coletado Caso de uso
Diretórios de prestadores (NPI) CAPTCHA de imagem Busca por médico ou instituição Adequação de rede
Portais de preço de medicamento reCAPTCHA v2 Preço de medicamentos Transparência de preços
Registros de ensaios clínicos reCAPTCHA v2 Dados e resultados do ensaio Análise de pesquisa
Formulários de seguro (formulary) reCAPTCHA v2 Lista de cobertura de medicamentos Comparação de formulário
Conselhos estaduais de licenciamento CAPTCHA de imagem Verificação de licença Checagem de credenciais
Classificação de qualidade hospitalar Cloudflare Turnstile Métricas de qualidade Análise de desempenho

LGPD, HIPAA e dados de saúde: o que pode ser coletado

A pergunta que trava mais projetos de coleta de dados de saúde não é técnica, é jurídica: esse dado é PHI (informação de saúde protegida) ou não? A HIPAA regula apenas PHI — prontuário, diagnóstico, atendimento vinculado a uma pessoa identificável. Diretório de prestador, preço de medicamento e metadado de ensaio clínico não são PHI: são registros públicos que a regra de transparência de preços do CMS incentiva a circular.

Se sua equipe opera a partir do Brasil e processa esse dado — mesmo vindo de um portal americano —, a LGPD entra em cena no tratamento feito aqui: defina uma base legal, armazene só os campos necessários para a análise e nunca guarde identificador de paciente, mesmo que o portal de origem o exponha por engano.

Tipo de dado Sensibilidade Recomendação
Diretórios de prestadores Baixa (informação pública) Coleta geralmente segura
Preço de medicamentos Baixa (preço público) Permitido para transparência
Metadado de ensaios clínicos Baixa (registro público) Uso de pesquisa apropriado
Avaliações de pacientes Média Anonimizar antes da análise
Detalhe de plano de seguro Baixa (taxa publicada) Permitido para comparação

Importante: nunca tente coletar informação de saúde protegida (PHI). Trabalhe apenas com dado público e não específico de paciente.


Script Python para diretórios de prestadores e preços de medicamentos

A classe abaixo cobre os dois cenários mais comuns: busca em diretório de prestadores (CAPTCHA de imagem ou reCAPTCHA v2, dependendo do portal) e consulta de preço de medicamento por CEP. As funções solve_recaptcha e solve_image_captcha seguem o padrão de fila da CaptchaAI: enviam a tarefa para in.php e consultam res.php a cada poucos segundos até o token voltar. O método batch_provider_lookup percorre especialidades e localizações em sequência e exporta tudo para CSV.

import requests
import time
import re
import base64
from bs4 import BeautifulSoup
import csv

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"


def solve_recaptcha(sitekey, pageurl):
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY, "method": "userrecaptcha",
        "googlekey": sitekey, "pageurl": pageurl, "json": 1,
    })
    task_id = resp.json()["request"]
    for _ in range(60):
        time.sleep(5)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]
    raise TimeoutError("Timeout")


def solve_image_captcha(image_bytes):
    img_b64 = base64.b64encode(image_bytes).decode()
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY, "method": "base64",
        "body": img_b64, "json": 1,
    })
    task_id = resp.json()["request"]
    for _ in range(20):
        time.sleep(3)
        result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = result.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]
    raise TimeoutError("Timeout")


class HealthcareDataCollector:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        if proxy:
            self.session.proxies = {"http": proxy, "https": proxy}
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
        })

    def search_providers(self, portal_url, specialty, location, sitekey=None):
        """Search provider directory with CAPTCHA handling."""
        resp = self.session.get(portal_url, timeout=30)

        data = {"specialty": specialty, "location": location}

        # Handle CAPTCHA
        if sitekey:
            token = solve_recaptcha(sitekey, portal_url)
            data["g-recaptcha-response"] = token
        else:
            captcha_img = re.search(r'src="(/captcha[^"]+)"', resp.text)
            if captcha_img:
                img_url = portal_url.rstrip("/") + captcha_img.group(1)
                img = self.session.get(img_url)
                data["captcha"] = solve_image_captcha(img.content)

        resp = self.session.post(portal_url, data=data)
        return self._parse_providers(resp.text)

    def lookup_drug_prices(self, pricing_url, drug_name, zip_code, sitekey):
        """Look up drug prices with CAPTCHA solving."""
        # Load search page
        self.session.get(pricing_url)

        # Solve CAPTCHA
        token = solve_recaptcha(sitekey, pricing_url)

        resp = self.session.post(pricing_url, data={
            "drug": drug_name,
            "zip": zip_code,
            "g-recaptcha-response": token,
        })

        if resp.status_code == 200:
            return self._parse_prices(resp.text)
        return []

    def batch_provider_lookup(self, portal_url, specialties, locations, output_file):
        """Batch search across specialties and locations."""
        all_providers = []

        for specialty in specialties:
            for location in locations:
                try:
                    providers = self.search_providers(
                        portal_url, specialty, location,
                    )
                    for p in providers:
                        p["specialty_search"] = specialty
                        p["location_search"] = location
                    all_providers.extend(providers)
                    print(f"{specialty} / {location}: {len(providers)} providers")
                    time.sleep(5)
                except Exception as e:
                    print(f"Error: {specialty} / {location}: {e}")

        # Export
        if all_providers:
            keys = all_providers[0].keys()
            with open(output_file, "w", newline="", encoding="utf-8") as f:
                writer = csv.DictWriter(f, fieldnames=keys)
                writer.writeheader()
                writer.writerows(all_providers)

        return all_providers

    def _parse_providers(self, html):
        soup = BeautifulSoup(html, "html.parser")
        providers = []
        for card in soup.select(".provider-card, .doctor-result, tr.provider"):
            providers.append({
                "name": self._text(card, ".name, .provider-name"),
                "specialty": self._text(card, ".specialty"),
                "address": self._text(card, ".address"),
                "phone": self._text(card, ".phone"),
                "accepting": self._text(card, ".accepting-patients"),
            })
        return providers

    def _parse_prices(self, html):
        soup = BeautifulSoup(html, "html.parser")
        prices = []
        for row in soup.select(".pharmacy-row, .price-result"):
            prices.append({
                "pharmacy": self._text(row, ".pharmacy-name"),
                "price": self._text(row, ".price, .drug-price"),
                "quantity": self._text(row, ".quantity"),
            })
        return prices

    def _text(self, el, selector):
        found = el.select_one(selector)
        return found.get_text(strip=True) if found else ""


# Usage
collector = HealthcareDataCollector(
    proxy="http://user:[email protected]:5000"
)

# Provider search
providers = collector.search_providers(
    portal_url="https://provider-directory.example.com/search",
    specialty="Cardiology",
    location="New York, NY",
)

# Drug pricing
prices = collector.lookup_drug_prices(
    pricing_url="https://drug-prices.example.com/compare",
    drug_name="atorvastatin",
    zip_code="10001",
    sitekey="6Lc_xxxxxxx",
)

Coleta de dados de ensaios clínicos

Registros de ensaios clínicos expõem status, patrocinador, fase e local de recrutamento — protegidos por reCAPTCHA v2 na maioria dos portais. A função collect_clinical_trials reaproveita a classe HealthcareDataCollector e filtra estudos com status="recruiting".

def collect_clinical_trials(search_url, condition, sitekey):
    """Collect clinical trial data for a medical condition."""
    collector = HealthcareDataCollector(
        proxy="http://user:[email protected]:5000"
    )

    token = solve_recaptcha(sitekey, search_url)
    resp = collector.session.post(search_url, data={
        "condition": condition,
        "status": "recruiting",
        "g-recaptcha-response": token,
    })

    if resp.status_code != 200:
        return []

    soup = BeautifulSoup(resp.text, "html.parser")
    trials = []
    for item in soup.select(".trial-item, .study-result"):
        trials.append({
            "title": collector._text(item, ".title, h3"),
            "status": collector._text(item, ".status"),
            "sponsor": collector._text(item, ".sponsor"),
            "phase": collector._text(item, ".phase"),
            "enrollment": collector._text(item, ".enrollment"),
            "location": collector._text(item, ".location"),
        })

    return trials

Qual plano da CaptchaAI faz sentido para esse volume

A CaptchaAI cobra por thread simultânea, não por CAPTCHA resolvido — todo plano inclui solves ilimitados dentro das threads contratadas. Para dimensionar, pense em quantas buscas rodam ao mesmo tempo, não em quantas horas o script fica ligado.

Cenário Threads simultâneas Plano recomendado
Consulta de preço em uma farmácia por vez, uso pontual 1–5 BASIC (US$ 15/mês, 5 threads)
Auditoria semanal de preços em várias regiões 10–15 STANDARD (US$ 30/mês, 15 threads)
Coleta diária em dezenas de diretórios de prestadores em paralelo 30–50 ADVANCE (US$ 90/mês, 50 threads)

Se os workers rodam a partir de São Paulo (sa-east-1), o RTT até os portais americanos soma alguns milissegundos por requisição — irrelevante em lote noturno, mas vale medir em fluxo quase em tempo real.


Solução de problemas comuns

A maioria dos erros nessa coleta cai em cinco padrões:

Problema Causa Correção
CAPTCHA de imagem ilegível Imagem de baixa qualidade Tente de novo — o portal gera uma imagem nova a cada tentativa
Busca de prestador volta vazia CAPTCHA bloqueou a busca Resolva o CAPTCHA antes de enviar o formulário, nunca depois
Preço de medicamento varia por região Preço calculado por geolocalização Combine a localização do proxy com o CEP consultado
Sessão expira em buscas de várias páginas Timeout do portal Complete a busca rapidamente
Taxa limitada em buscas em lote Muitas requisições seguidas Adicione atrasos de 5 a 10 segundos entre chamadas

Perguntas frequentes

Preciso me preocupar com a LGPD se o portal de origem é americano?

Sim, se o tratamento do dado acontece no Brasil. A LGPD regula o processamento feito aqui, mesmo que a fonte seja um portal dos EUA — defina uma base legal, colete só os campos necessários e nunca armazene identificador de paciente.

Diretório de prestador e preço de medicamento contam como PHI pela HIPAA?

Não. PHI é informação vinculada a um paciente identificável — prontuário, diagnóstico, atendimento individual. Diretório de prestador, preço de medicamento e metadado de ensaio clínico são registros públicos e não PHI. O que nunca deve ser coletado é o registro individual de um paciente.

Quantas threads eu preciso para monitorar preço de medicamento em vários estados?

Depende de quantas consultas rodam ao mesmo tempo, não do total de CEPs monitorados. Uma auditoria semanal que consulta uma região por vez cabe no plano BASIC (5 threads); rodar dezenas de regiões em paralelo todo dia já pede STANDARD ou ADVANCE.

O CAPTCHA de imagem dos conselhos de licenciamento falha toda hora — o que fazer?

Normalmente é imagem de baixa qualidade renderizada pelo próprio portal, não falha da resolução. Tente novamente: a maioria desses conselhos gera uma imagem nova a cada tentativa.


Guias relacionados


Comece agora: crie sua chave de API na CaptchaAI e automatize a próxima busca em diretório de prestadores ou portal de preço de medicamento.

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