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
- Automação de portais governamentais
- Coleta de dados de pesquisa acadêmica protegidos por CAPTCHA
- Rotação de proxies para coleta de dados em escala
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.