Sí: la mayoría de los datos sanitarios que necesitas para un análisis serio (directorios de médicos, precios de medicamentos, metadatos de ensayos clínicos, listas de cobertura de seguros) son información pública y puedes recopilarlos de forma automatizada. El obstáculo casi nunca es el permiso legal, sino el CAPTCHA que el portal pone delante del formulario de búsqueda. Cuando envías consultas a ritmo de máquina, aparece un reCAPTCHA v2, un CAPTCHA de imagen o un Cloudflare Turnstile, y tu raspador se detiene en seco.
CaptchaAI resuelve exactamente esos tipos por API, así que tu código sigue el mismo flujo que un usuario real: carga la página, obtiene el token del CAPTCHA y envía el formulario. Esta guía lo hace en Python para un directorio de proveedores y un registro de ensayos clínicos: qué datos puedes tocar sin cruzar líneas legales y cómo escalar sin que el coste se dispare.
Dónde te encontrarás CAPTCHA en portales sanitarios
Antes de escribir una sola línea, conviene saber qué reto protege cada fuente. Casi todos los portales sanitarios se apoyan en tres familias, las tres compatibles con CaptchaAI:
- reCAPTCHA v2 — precios de medicamentos, formularios de seguros y registros de ensayos.
- CAPTCHA de imagen (OCR) — directorios de proveedores y juntas de licencias.
- Cloudflare Turnstile — portales de calidad hospitalaria.
La tabla resume cada caso.
| Fuente | Tipo de CAPTCHA | Dato | Caso de uso |
|---|---|---|---|
| Directorios de proveedores (NPI) | CAPTCHA de imagen | Búsqueda de médicos y centros | Adecuación de la red |
| Portales de precios de medicamentos | reCAPTCHA v2 | Precios de fármacos | Transparencia de precios |
| Registros de ensayos clínicos | reCAPTCHA v2 | Datos y resultados de ensayos | Análisis de investigación |
| Formularios de seguros | reCAPTCHA v2 | Listas de cobertura de fármacos | Comparación de coberturas |
| Juntas de licencias profesionales | CAPTCHA de imagen | Verificación de licencias | Comprobación de credenciales |
| Calificaciones de calidad hospitalaria | Cloudflare Turnstile | Métricas de calidad | Análisis de desempeño |
Extraer un directorio de proveedores en Python
El siguiente colector encapsula la lógica repetitiva: una sesión de requests con cabeceras realistas, una función que resuelve reCAPTCHA v2 y otra que resuelve el CAPTCHA de imagen. search_providers decide cuál usar según reciba o no un sitekey, adjunta el token en el campo g-recaptcha-response y devuelve la ficha ya parseada. batch_provider_lookup recorre especialidades y ubicaciones, y exporta todo a 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:pass@residential.proxy.com: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",
)
El campo zip_code importa: muchos portales muestran tarifas distintas según la geografía, así que conviene alinear tu salida de red autorizada con el código postal que consultas.
Recopilar datos de ensayos clínicos
Los registros de ensayos exponen metadatos de gran valor (título, fase, patrocinador, estado de reclutamiento) y suelen protegerse con reCAPTCHA v2. Reutiliza el colector anterior: resuelve el CAPTCHA una vez, envía la búsqueda por condición médica y parsea los resultados.
def collect_clinical_trials(search_url, condition, sitekey):
"""Collect clinical trial data for a medical condition."""
collector = HealthcareDataCollector(
proxy="http://user:pass@residential.proxy.com: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
Qué datos puedes recopilar sin cruzar líneas legales
Aquí es donde más gente se equivoca: lo que recopilas debe ser público y no identificable con un paciente. Piensa en una plataforma de tecnología sanitaria en España que compara precios de medicamentos entre farmacias o mide la cobertura de la red de un seguro: todos esos datos son tarifas y directorios publicados, no historiales clínicos.
| Tipo de dato | Sensibilidad | Recomendación |
|---|---|---|
| Directorios de proveedores | Baja (información pública) | Generalmente seguro de recopilar |
| Precios de medicamentos | Baja (precios públicos) | Permitido por transparencia |
| Metadatos de ensayos clínicos | Baja (registros públicos) | Uso apropiado en investigación |
| Reseñas de pacientes | Media | Anonimiza antes de analizar |
| Detalles de planes de seguros | Baja (tarifas publicadas) | Permitido para comparación |
Importante: nunca intentes recopilar información sanitaria protegida (PHI en el marco HIPAA, categoría especial bajo el RGPD y la LOPDGDD en España). Céntrate solo en datos públicos y no específicos de pacientes, y respeta los términos de servicio de cada portal y la normativa de protección de datos aplicable.
Errores frecuentes y cómo resolverlos
| Problema | Causa | Solución |
|---|---|---|
| Imagen CAPTCHA ilegible | Imagen de baja calidad | Reintenta: se genera una imagen nueva |
| La búsqueda de proveedores vuelve vacía | El CAPTCHA bloqueó la búsqueda | Resuelve el CAPTCHA antes de enviar |
| El precio del fármaco varía según la ubicación | Precios por geografía | Haz coincidir la ubicación del proxy con el código postal |
| La sesión caduca entre páginas | Tiempo de espera del portal | Completa las búsquedas con rapidez |
| Límite de solicitudes en búsquedas por lotes | Demasiadas solicitudes | Añade retrasos de 5 a 10 segundos |
Escala y coste con planes por thread
Al pasar de una prueba puntual a un barrido diario de decenas de miles de búsquedas, el precio importa tanto como el código. CaptchaAI cobra por thread concurrente, no por CAPTCHA resuelto: cada plan incluye solves ilimitados durante el mes y un thread es un CAPTCHA en curso que queda libre para el siguiente al terminar. Para un equipo que factura en moneda local volátil, este coste fijo en USD es más fácil de presupuestar que el pago por resolución.
Dos puntos de partida según tu volumen:
- BASIC ($15/mes, 5 threads) — para validar la integración antes de escalar.
- ADVANCE ($90/mes, 50 threads) — cuando
batch_provider_lookuprecorre muchas especialidades y ubicaciones en paralelo; cada thread es una búsqueda simultánea más.
Los retrasos de 5 a 10 segundos entre solicitudes evitan que el portal te aplique un límite. Consulta las cifras actualizadas en la página de precios de captchaai.com.
Preguntas frecuentes
¿Qué tipos de CAPTCHA resuelve CaptchaAI en portales sanitarios?
Los tres que verás casi siempre: reCAPTCHA v2, CAPTCHA de imagen (OCR) y Cloudflare Turnstile. Todos son compatibles y se resuelven por la misma API con el method correspondiente.
¿Necesito un proxy para recopilar estos datos?
Depende del portal. Muchos toleran búsquedas moderadas sin él, pero para lotes grandes o precios que dependen de la geografía conviene una salida de red autorizada cuya ubicación coincida con el código postal que consultas.
¿Cómo cumplo con el RGPD y la HIPAA al recopilar datos sanitarios?
La HIPAA cubre la información sanitaria protegida (PHI) y el RGPD trata los datos de salud como categoría especial. Los directorios de proveedores, los precios de medicamentos y los registros públicos de ensayos no son datos de pacientes y quedan fuera de ese ámbito. Nunca extraigas registros individuales.
¿Qué plan conviene para búsquedas por lotes?
Empieza con BASIC ($15/mes, 5 threads) para las pruebas y escala a ADVANCE ($90/mes, 50 threads) cuando lances barridos con muchas especialidades en paralelo; los threads son búsquedas simultáneas y los solves son ilimitados.
Guías relacionadas
- Automatización de portales gubernamentales con CAPTCHA
- Scraping de investigación académica
- Resolución de CAPTCHA para QA y pruebas autorizadas
Recopila datos sanitarios públicos sin fricción: consigue tu clave de CaptchaAI y automatiza las búsquedas de proveedores y precios.