La forma directa de recopilar precios de medicamentos de portales protegidos es delegar cada CAPTCHA a un servicio de resolución. El patrón es siempre el mismo:
- Extrae el sitekey del HTML de la página de búsqueda.
- Envía ese sitekey a CaptchaAI y sondea su API hasta recibir el token.
- Reenvía el token en el campo que espera el formulario (
g-recaptcha-response,cf-turnstile-response…).
Con ese flujo, un comparador puede consultar decenas de fuentes —farmacias online, bases de datos de medicamentos y formularios de seguros— sin que el reCAPTCHA v2, el Cloudflare Turnstile o el CAPTCHA de imagen de cada sitio corten la recopilación. A continuación tienes la implementación completa en Python y JavaScript.
Dónde encuentras CAPTCHA en los portales de farmacia
Antes de escribir código conviene saber qué proteges: cada tipo de página suele disparar un desafío distinto, y eso determina qué método y qué campo de token necesitas.
- Formulario de búsqueda de medicamentos — reCAPTCHA v2 en cada consulta.
- Página de resultados de precios — Cloudflare Turnstile ante accesos automatizados sospechosos.
- Localizador de farmacias — reCAPTCHA v2 en consultas por ubicación.
- Buscador de cupones — CAPTCHA de imagen antes de mostrar los códigos de descuento.
- Formulario de seguro — reCAPTCHA v2 en las puertas de inicio de sesión o búsqueda.
Cuánto cuesta comparar precios a escala
Conviene dimensionar el plan antes de programar, porque la capacidad de CaptchaAI se traduce directamente en cuántas farmacias puedes consultar en paralelo. CaptchaAI factura por thread concurrente —no por resolución— y cada plan incluye resoluciones ilimitadas durante el mes; un thread es un CAPTCHA en curso, y en cuanto termina queda libre para el siguiente.
- BASIC ($15/mes, 5 threads) — un comparador pequeño que refresca unas pocas fuentes.
- ADVANCE ($90/mes, 50 threads) — muchos precios cruzados a la vez.
- PREMIUM ($170/mes, 100 threads) — catálogos amplios con refrescos frecuentes.
Este costo mensual predecible en USD suele resultar más manejable para agencias y freelancers que facturan en monedas locales volátiles que un modelo de pago por resolución. Un apunte antes de desplegar: respeta los términos de servicio de cada portal y la normativa de protección de datos aplicable —GDPR y LOPDGDD en España, LFPDPPP en México y equivalentes en la región— y enfoca la recopilación como monitorización de flujos autorizados.
Flujo básico de resolución
El núcleo del comparador es una función que resuelve un reCAPTCHA v2 y devuelve el token. Envía el sitekey al endpoint in.php, sondea res.php cada tres segundos hasta que la resolución termina y adjunta el g-recaptcha-response a la petición de búsqueda:
import requests
import time
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def solve_recaptcha(site_key, page_url):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("Solve timed out")
def search_drug_prices(drug_name, zipcode):
search_url = "https://pharmacy.example.com/search"
# Load the search page to get the site key
page = session.get(search_url)
# Extract reCAPTCHA site key
import re
match = re.search(r'data-sitekey="([^"]+)"', page.text)
site_key = match.group(1)
# Solve the CAPTCHA
token = solve_recaptcha(site_key, search_url)
# Submit the search with token
results = session.post(search_url, data={
"drug": drug_name,
"zip": zipcode,
"g-recaptcha-response": token
})
return parse_prices(results.text)
Comparar varias farmacias a la vez
El valor de un comparador está en cruzar precios de varias fuentes para el mismo medicamento. Recorre la lista de portales, captura los errores por fuente para que un fallo no tumbe toda la ejecución y ordena por el precio más bajo:
PHARMACY_SOURCES = [
{
"name": "PharmacyA",
"url": "https://pharmacya.example.com/pricing",
"captcha_type": "recaptcha_v2"
},
{
"name": "PharmacyB",
"url": "https://pharmacyb.example.com/drugs",
"captcha_type": "turnstile"
},
{
"name": "PharmacyC",
"url": "https://pharmacyc.example.com/search",
"captcha_type": "image"
}
]
def compare_drug_price(drug_name, zipcode):
results = []
for source in PHARMACY_SOURCES:
try:
prices = fetch_prices(
source["url"],
source["captcha_type"],
drug_name,
zipcode
)
results.append({
"source": source["name"],
"prices": prices,
"status": "success"
})
except Exception as e:
results.append({
"source": source["name"],
"error": str(e),
"status": "failed"
})
return sorted(results, key=lambda r: r.get("prices", {}).get("lowest", float("inf")))
Gestionar distintos tipos de CAPTCHA
Cada portal puede usar un proveedor diferente, así que conviene una sola función que decida el método y el campo del token según el tipo detectado:
- reCAPTCHA v2 → método
userrecaptcha, campog-recaptcha-response. - Cloudflare Turnstile → método
turnstile, campocf-turnstile-response. - CAPTCHA de imagen → OCR, campo
captcha.
def fetch_prices(url, captcha_type, drug_name, zipcode):
page = session.get(url)
if captcha_type == "recaptcha_v2":
import re
match = re.search(r'data-sitekey="([^"]+)"', page.text)
token = solve_recaptcha(match.group(1), url)
field_name = "g-recaptcha-response"
elif captcha_type == "turnstile":
import re
match = re.search(r'data-sitekey="(0x[^"]+)"', page.text)
token = solve_turnstile(match.group(1), url)
field_name = "cf-turnstile-response"
elif captcha_type == "image":
img_data = extract_captcha_image(page.text)
token = solve_image_captcha(img_data)
field_name = "captcha"
return session.post(url, data={
"drug": drug_name,
"zip": zipcode,
field_name: token
})
CaptchaAI resuelve reCAPTCHA v2/v3, Cloudflare Turnstile y Challenge, GeeTest v3 y CAPTCHA de imagen y grid, de modo que puedes añadir una farmacia nueva sin rehacer tu arquitectura: solo mapeas su captcha_type al método correspondiente.
Reutilizar sesiones para búsquedas repetidas
Comparar precios implica muchas consultas, y no todas disparan un CAPTCHA. Mantén las cookies vivas y resuelve solo cuando la página lo exija; así reduces resoluciones innecesarias y cuidas tu saldo:
class PharmacySession:
def __init__(self, base_url):
self.session = requests.Session()
self.base_url = base_url
self.searches_since_captcha = 0
def search(self, drug_name, zipcode):
result = self.session.post(f"{self.base_url}/search", data={
"drug": drug_name,
"zip": zipcode
})
if self.is_captcha_page(result.text):
token = self.solve_page_captcha(result.text)
result = self.session.post(f"{self.base_url}/search", data={
"drug": drug_name,
"zip": zipcode,
"g-recaptcha-response": token
})
self.searches_since_captcha = 0
else:
self.searches_since_captcha += 1
return result
def is_captcha_page(self, html):
return "g-recaptcha" in html or "cf-turnstile" in html
def solve_page_captcha(self, html):
import re
match = re.search(r'data-sitekey="([^"]+)"', html)
return solve_recaptcha(match.group(1), self.base_url)
Implementación en JavaScript
Si tu comparador vive en Node.js, el mismo patrón se traduce directo: resuelve el CAPTCHA de cada fuente en paralelo con Promise.all, descarta las que fallan y ordena por precio.
async function comparePharmacyPrices(drugName, zipCode, sources) {
const results = await Promise.all(
sources.map(async (source) => {
try {
const price = await fetchDrugPrice(source, drugName, zipCode);
return { source: source.name, price, status: 'success' };
} catch (error) {
return { source: source.name, error: error.message, status: 'failed' };
}
})
);
return results
.filter(r => r.status === 'success')
.sort((a, b) => a.price - b.price);
}
async function fetchDrugPrice(source, drugName, zipCode) {
// Solve CAPTCHA for this source
const token = await solveCaptcha(source.siteKey, source.url);
const response = await fetch(source.url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
drug: drugName,
zip: zipCode,
'g-recaptcha-response': token
})
});
return parsePrice(await response.text());
}
Controlar la frecuencia de solicitudes
Los portales de farmacia vigilan de cerca los patrones de acceso, y un ritmo demasiado agresivo dispara más desafíos —cuando no un bloqueo temporal—. Cuatro medidas mantienen el comparador estable:
- Espacia las solicitudes 5 a 10 segundos entre búsquedas.
- Rota de sesión cada 20–30 consultas.
- Varía los patrones de búsqueda: no repitas el mismo medicamento una y otra vez.
- Sal por una red autorizada; las IP de centro de datos disparan más CAPTCHA.
Resolución de problemas
Cuando la recopilación empieza a fallar, casi siempre es una de estas cuatro causas:
- CAPTCHA en cada búsqueda — las cookies de sesión no persisten; usa
requests.Session()y consérvalas. - Los precios no cargan tras el CAPTCHA — falta el token CSRF; extrae e incluye los campos ocultos del formulario.
- Bloqueos tras muchas búsquedas — límite de solicitudes; añade retrasos entre peticiones.
- Precios distintos a los del navegador — faltan cookies o cabeceras de sesión; reprodúcelas con exactitud.
Preguntas frecuentes
¿Qué plan de CaptchaAI necesito para comparar precios a escala?
Depende de cuántas farmacias consultes en paralelo. Como CaptchaAI factura por thread concurrente con resoluciones ilimitadas, el plan BASIC ($15/mes, 5 threads) cubre un comparador pequeño, mientras que ADVANCE ($90/mes, 50 threads) o PREMIUM ($170/mes, 100 threads) encajan cuando refrescas muchos precios a la vez. Encontrarás la tabla completa en la página de precios de captchaai.com.
¿Puedo resolver reCAPTCHA v2 y Turnstile con la misma integración?
Sí. La API usa el mismo flujo de envío y sondeo para ambos; solo cambian el método (userrecaptcha o turnstile) y el nombre del campo del token (g-recaptcha-response frente a cf-turnstile-response). Tu función de comparación reutiliza la misma lógica de resolución para todas las fuentes.
¿Por qué aparecen más CAPTCHA cuando ejecuto el comparador desde un servidor?
Porque las IP de centro de datos tienen peor reputación que las domésticas y provocan más desafíos. Espaciar las solicitudes, conservar las cookies de sesión y salir por una red autorizada reducen la frecuencia con la que los portales muestran un CAPTCHA.
¿Cambia el manejo de CAPTCHA entre medicamentos de marca y genéricos?
Poco. Las bases de datos de genéricos a veces usan CAPTCHA de imagen más simples, mientras que los portales de marca suelen apoyarse en reCAPTCHA v2 o Turnstile. El patrón de extraer el sitekey, resolver y reenviar el token es idéntico en ambos casos.
Artículos relacionados
- Resolver el callback de reCAPTCHA v2 con la API
- Manejar reCAPTCHA v2 y Turnstile en el mismo sitio
- Cómo funciona el mecanismo de callback de reCAPTCHA v2
Próximos pasos
Monta tu comparador de precios de farmacia: consigue tu API key de CaptchaAI y resuelve los CAPTCHA de todas tus fuentes desde una sola integración.