La decisión al montar un scraper protegido por CAPTCHA es corta: deja que Oxylabs se encargue de la salida de red y que CaptchaAI resuelva cada reCAPTCHA v2 o Cloudflare Turnstile. El centro de datos da velocidad y volumen; los residenciales generan menos desafíos. En ambos casos el CAPTCHA deja de ser un muro y pasa a ser una llamada a la API. Esta guía conecta los proxies de Oxylabs con CaptchaAI en Python, con ejemplos listos para copiar. Si ya vienes de 2Captcha o Anti-Captcha, la integración es familiar: CaptchaAI expone los mismos endpoints in.php / res.php, así que reutilizas casi toda tu lógica de envío y sondeo.
En este montaje cada pieza tiene un papel claro:
- Oxylabs aporta la salida de red: IP, rotación y país de origen de la petición.
- CaptchaAI resuelve el desafío y te devuelve el token que valida el formulario.
- Tu código orquesta ambos: obtiene la página, detecta el
sitekeyy envía el token.
Qué proxy de Oxylabs elegir
Oxylabs tiene varias familias de proxies y no todas encajan igual con un flujo con CAPTCHA. Esta tabla resume cuándo tira cada una:
| Producto | IP | Velocidad | Caso de uso |
|---|---|---|---|
| Datacenter Proxies | 2 M+ | Muy rápida | Alto volumen, prioridad a la velocidad |
| Residential Proxies | 100 M+ | Media | Sitios sensibles a CAPTCHA |
| ISP Proxies | Grado residencial | Rápida | E-commerce, redes sociales |
| Mobile Proxies | 20 M+ | Lenta | Objetivos móviles |
| SERP Scraper API | Gestionado | Rápida | Resultados de Google/Bing |
El atajo mental: objetivo sensible, IP residencial; prioridad a la velocidad, centro de datos, porque CaptchaAI absorbe los CAPTCHA que se generen de todos modos.
Integración en Python con requests
Enruta la petición por el proxy de Oxylabs y delega el reCAPTCHA en CaptchaAI. El sufijo -cc-{country} fija el país de salida. La función solve_recaptcha envía la tarea a in.php, luego sondea res.php cada cinco segundos: mientras la respuesta sea CAPCHA_NOT_READY sigue esperando, y devuelve el token en cuanto está resuelto o lanza un TimeoutError tras el límite de intentos.
import requests
import time
OXYLABS_USER = "customer-USERNAME"
OXYLABS_PASS = "PASSWORD"
OXYLABS_ENDPOINT = "pr.oxylabs.io:7777"
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
# Residential rotating proxy
proxies = {
"http": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
"https": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
}
def fetch_page(url, country=None):
"""Fetch page through Oxylabs proxy."""
user = OXYLABS_USER
if country:
user += f"-cc-{country}"
proxy = {
"http": f"http://{user}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
"https": f"http://{user}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}",
}
return requests.get(
url,
proxies=proxy,
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36"
},
timeout=30,
)
def solve_recaptcha(site_url, sitekey):
"""Solve via CaptchaAI."""
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
"key": CAPTCHAAI_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": site_url,
"json": 1,
})
data = resp.json()
if data["status"] != 1:
raise Exception(f"Submit: {data['request']}")
task_id = data["request"]
for _ in range(60):
time.sleep(5)
resp = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY,
"action": "get",
"id": task_id,
"json": 1,
})
data = resp.json()
if data["request"] == "CAPCHA_NOT_READY":
continue
if data["status"] == 1:
return data["request"]
raise Exception(f"Solve: {data['request']}")
raise TimeoutError("Timeout")
Mantener la misma IP con sesiones persistentes
Si el formulario carga el CAPTCHA en una petición y valida el token en otra, necesitas la misma IP en ambas: la sesión persistente de Oxylabs se activa con el sufijo -sessid-{session_id}.
def get_oxylabs_sticky_proxy(session_id, country=None):
"""Create Oxylabs sticky session (same IP)."""
user = OXYLABS_USER + f"-sessid-{session_id}"
if country:
user += f"-cc-{country}"
proxy_url = f"http://{user}:{OXYLABS_PASS}@{OXYLABS_ENDPOINT}"
return {"http": proxy_url, "https": proxy_url}
# CAPTCHA workflow with sticky IP
import random, string
session = "".join(random.choices(string.ascii_lowercase, k=8))
proxy = get_oxylabs_sticky_proxy(session, country="us")
# All requests use the same IP
resp = requests.get("https://target.com/form", proxies=proxy)
# ... solve CAPTCHA ...
resp = requests.post("https://target.com/submit", proxies=proxy, data={
"g-recaptcha-response": token,
})
Oxylabs Web Scraper API + CaptchaAI
Si el renderizado propio de Oxylabs no basta, la Web Scraper API te entrega el HTML renderizado y CaptchaAI resuelve en cuanto detectas un data-sitekey.
def scrape_with_oxylabs_api(url):
"""Use Oxylabs Web Scraper API for rendering, CaptchaAI for CAPTCHAs."""
resp = requests.post(
"https://realtime.oxylabs.io/v1/queries",
auth=(OXYLABS_USER, OXYLABS_PASS),
json={
"source": "universal",
"url": url,
"render": "html",
"browser_instructions": [
{"type": "wait", "wait_time_s": 3},
],
},
)
result = resp.json()
html = result["results"][0]["content"]
# Check for CAPTCHA in rendered HTML
import re
sitekey_match = re.search(r'data-sitekey="([^"]+)"', html)
if sitekey_match:
sitekey = sitekey_match.group(1)
token = solve_recaptcha(url, sitekey)
return {"html": html, "captcha_solved": True, "token": token}
return {"html": html, "captcha_solved": False}
Centro de datos vs residencial ante los CAPTCHA
Decide por objetivo, no para todo el proyecto: residencial para los dominios que reaccionan al tráfico automatizado y centro de datos para el resto, donde manda la velocidad. smart_proxy_selection encapsula esa lógica en una sola función, de modo que el resto del pipeline no tiene que saber qué tipo de IP está usando.
# Datacenter: Fast but higher CAPTCHA rate
DC_PROXY = {
"http": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@dc.pr.oxylabs.io:10000",
"https": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@dc.pr.oxylabs.io:10000",
}
# Residential: Slower but lower CAPTCHA rate
RES_PROXY = {
"http": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@pr.oxylabs.io:7777",
"https": f"http://{OXYLABS_USER}:{OXYLABS_PASS}@pr.oxylabs.io:7777",
}
def smart_proxy_selection(url, captcha_sensitive=True):
"""Pick proxy type based on target site sensitivity."""
if captcha_sensitive:
return RES_PROXY # Less likely to trigger CAPTCHA
return DC_PROXY # Faster, CaptchaAI handles any CAPTCHAs
Pipeline concurrente
CaptchaAI factura por thread concurrente, sin coste por resolución. Este ThreadPoolExecutor procesa varias URL en paralelo, cada una con su sesión persistente. Ajusta max_workers a los threads de tu plan: con 5 threads del plan BASIC, cinco resoluciones simultáneas mantienen el pipeline saturado sin desperdiciar capacidad.
from concurrent.futures import ThreadPoolExecutor, as_completed
def process_url(url):
session = "".join(random.choices(string.ascii_lowercase, k=8))
proxy = get_oxylabs_sticky_proxy(session, country="us")
try:
resp = requests.get(url, proxies=proxy, timeout=30)
import re
match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if match:
token = solve_recaptcha(url, match.group(1))
return {"url": url, "status": "solved"}
return {"url": url, "status": "no_captcha"}
except Exception as e:
return {"url": url, "status": "error", "error": str(e)}
urls = ["https://site1.com", "https://site2.com", "https://site3.com"]
with ThreadPoolExecutor(max_workers=5) as executor:
futures = {executor.submit(process_url, u): u for u in urls}
for future in as_completed(futures):
print(future.result())
Escenario: monitoreo de precios en España y LATAM
Caso típico: una agencia que monitorea precios de la competencia en marketplaces del tipo MercadoLibre o en Amazon.es para un panel diario, donde el reCAPTCHA salta ante varios accesos seguidos desde la misma IP. Los proxies de centro de datos de Oxylabs procesan miles de solicitudes por hora y CaptchaAI resuelve los reCAPTCHA sin frenar el pipeline, con costo mensual predecible en USD. Respeta siempre los términos de servicio y la normativa de protección de datos aplicable (GDPR y LOPDGDD en España, LFPDPPP en México).
Errores comunes y cómo resolverlos
- 403 desde el proxy: la IP está en una lista de bloqueo. Cambia a residencial o rota la IP.
- Fallo de autenticación: endpoint incorrecto. Centro de datos:
dc.pr.oxylabs.io:10000; residencial:pr.oxylabs.io:7777. - La sesión persistente caduca: dura unos 10 minutos por defecto. Genera un nuevo ID de sesión.
- CAPTCHA en cada página: la IP de centro de datos está reconocida. Usa una salida de red residencial autorizada.
- Respuesta lenta: latencia de la red residencial. Acéptala o cambia a los proxies de ISP.
Preguntas frecuentes
¿Cómo fijo el país de salida con Oxylabs?
Añade el sufijo -cc-{country} al usuario del proxy (por ejemplo, -cc-mx o -cc-es). Útil cuando el sitio cambia precios o contenido según la región.
¿Cuánto dura una sesión persistente y cómo la renuevo?
Por defecto ronda los 10 minutos. Cuando caduca, genera un nuevo session_id y reconstruye el proxy con -sessid- para obtener una IP fresca.
¿Qué tipos de CAPTCHA resuelve CaptchaAI en este flujo?
reCAPTCHA v2 y v3, Cloudflare Turnstile y Cloudflare Challenge, GeeTest v3, e imagen/OCR y grid. No resuelve hCaptcha ni FunCaptcha: planifica el objetivo según el tipo real de CAPTCHA.
¿Puedo resolver varios CAPTCHA en paralelo?
Sí. CaptchaAI factura por thread concurrente, no por resolución: el plan BASIC ($15/mes) incluye 5 threads y el STANDARD ($30/mes) sube a 15. Sube de plan cuando tu pipeline lance más resoluciones a la vez.
¿Es difícil migrar desde 2Captcha o Anti-Captcha?
No. CaptchaAI mantiene endpoints in.php / res.php compatibles con ese estilo de API, así que el cambio suele reducirse a apuntar la URL base a https://ocr.captchaai.com y usar tu nueva clave API; el flujo de envío y sondeo se queda casi igual.
Guías relacionadas
- Pruebas de QA autorizadas con CaptchaAI
- Resolución de CAPTCHA en entornos de prueba
- ISP frente a proxies de centro de datos
Combina la infraestructura de proxy de Oxylabs con la resolución de CaptchaAI: obtén tu clave API.