¿Tu scraper se topa con un CAPTCHA cada pocas páginas? Casi nunca es culpa del código: envías todo el tráfico desde una sola IP y el sitio lo detecta enseguida. Rotar proxies reparte esas solicitudes entre muchas direcciones para que ningún patrón por IP resulte sospechoso, y cuando aun así aparece un CAPTCHA, CaptchaAI lo resuelve por API sin frenar el flujo.
Un caso real: monitorear precios en marketplaces regionales
Imagina una agencia en Ciudad de México que sigue los precios de miles de productos en varios marketplaces de la región. Desde una sola IP, el sitio responde con CAPTCHA en minutos. Con un grupo de proxies cuya geografía coincide con cada dominio nacional, el tráfico parece de usuarios locales, la frecuencia de CAPTCHA cae y los pocos que se cuelan los resuelve CaptchaAI por API, con un costo mensual predecible en USD en vez de pagar por resolución.
Trabaja siempre sobre objetivos propios o autorizados y respeta los términos de servicio y la normativa de protección de datos aplicable (GDPR y LOPDGDD en España, LFPDPPP en México).
Qué dispara un CAPTCHA cuando usas una sola IP
Los sitios no bloquean al azar. Vigilan un puñado de señales por dirección y, cuando una IP se sale de lo normal, muestran el desafío:
- Solicitudes por minuto: pasar de 10 seguidas desde la misma IP suele bastar para disparar el CAPTCHA.
- Reputación de la IP: se degrada a medida que la dirección acumula actividad automatizada.
- Patrones de sesión: un comportamiento repetitivo y sin pausas delata al bot.
- Coherencia geográfica: todo el tráfico saliendo de una única ubicación resulta poco natural.
Cómo la rotación reparte esa carga
Al distribuir las solicitudes entre varias IP, cada dirección se mantiene por debajo de esos umbrales: menos solicitudes por minuto, reputación fresca en cada IP del grupo, patrones diluidos y una diversidad geográfica que se parece más al tráfico humano. El resultado es una frecuencia de CAPTCHA mucho más baja sin tocar la lógica del scraper.
Qué tipo de proxy elegir según el objetivo
No todos los proxies cuestan ni rinden igual; la elección depende de lo agresivo que sea el sistema anti-bot del sitio:
| Tipo | Mejor para | Frecuencia de CAPTCHA | Costo |
|---|---|---|---|
| Residencial | Objetivos exigentes (Google, Amazon) | Más baja | $$$ |
| Móvil | Detección mínima | Más baja | $$$$ |
| ISP/estático | Sesiones prolongadas | Baja | $$ |
| Centro de datos | Sitios tolerantes y de gran volumen | Más alta | $ |
Recomendación: para sitios con disparadores de CAPTCHA agresivos, usa proxies residenciales autorizados. Los de centro de datos rinden bien en sitios menos protegidos y salen mucho más baratos.
Rotación básica de proxies en Python
El patrón mínimo elige un proxy al azar en cada solicitud y, si detecta un CAPTCHA en la respuesta, lo envía a CaptchaAI para obtener el token:
import requests
import random
import time
PROXIES = [
"http://user:pass@proxy1.example.com:8080",
"http://user:pass@proxy2.example.com:8080",
"http://user:pass@proxy3.example.com:8080",
]
API_KEY = "YOUR_API_KEY"
def get_random_proxy():
proxy = random.choice(PROXIES)
return {"http": proxy, "https": proxy}
def scrape_with_rotation(url):
proxy = get_random_proxy()
session = requests.Session()
session.proxies = proxy
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
resp = session.get(url)
# If CAPTCHA appears, solve it
if "g-recaptcha" in resp.text or "captcha" in resp.text.lower():
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
rc = soup.find("div", class_="g-recaptcha")
if rc:
site_key = rc["data-sitekey"]
token = solve_captcha(site_key, url)
resp = session.post(url, data={"g-recaptcha-response": token})
return resp.text
def solve_captcha(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY, "method": "userrecaptcha",
"googlekey": site_key, "pageurl": page_url
})
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY": continue
if result.text.startswith("OK|"): return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError()
Rotación inteligente: prioriza las IP limpias
No todos los proxies rinden igual dentro del mismo grupo. Conviene un rotador que aprenda cuáles funcionan:
- Cuenta cuántos CAPTCHA recibe cada proxy.
- Calcula una tasa de éxito por IP.
- Da preferencia a la mitad mejor valorada al elegir la siguiente dirección.
from collections import defaultdict
import random
class SmartProxyRotator:
def __init__(self, proxies):
self.proxies = proxies
self.captcha_count = defaultdict(int)
self.success_count = defaultdict(int)
def get_proxy(self):
# Prefer proxies with lower CAPTCHA rates
scored = []
for proxy in self.proxies:
total = self.captcha_count[proxy] + self.success_count[proxy]
if total == 0:
score = 0.5 # Unknown proxy, neutral score
else:
score = self.success_count[proxy] / total
scored.append((proxy, score))
# Weight selection by score
scored.sort(key=lambda x: x[1], reverse=True)
top_proxies = scored[:max(len(scored) // 2, 1)]
proxy = random.choice(top_proxies)[0]
return proxy
def report_success(self, proxy):
self.success_count[proxy] += 1
def report_captcha(self, proxy):
self.captcha_count[proxy] += 1
# Usage
rotator = SmartProxyRotator(PROXIES)
def scrape(url):
proxy = rotator.get_proxy()
resp = requests.get(url, proxies={"http": proxy, "https": proxy})
if "captcha" in resp.text.lower():
rotator.report_captcha(proxy)
# Solve CAPTCHA...
else:
rotator.report_success(proxy)
return resp.text
Rotación de proxies con Selenium
Cuando necesitas un navegador real, asigna un proxy distinto a cada sesión al crear el driver:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def create_driver_with_proxy(proxy_url):
options = Options()
options.add_argument(f"--proxy-server={proxy_url}")
return webdriver.Chrome(options=options)
# Rotate proxy per session
proxy = random.choice(PROXIES)
driver = create_driver_with_proxy(proxy)
driver.get("https://example.com")
Proxy + resolución de CAPTCHA para Cloudflare Challenge
Cloudflare Challenge es el caso especial: el resultado queda ligado a la IP, así que hay que pasarle a CaptchaAI el mismo proxy con el que navegarás después:
proxy = "http://user:pass@proxy.example.com:8080"
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "cloudflare_challenge",
"pageurl": "https://example.com",
"proxy": proxy,
"proxytype": "HTTP"
})
task_id = resp.text.split("|")[1]
# Poll for qa_validation_cookie cookie
# Use the same proxy for subsequent requests
Problemas frecuentes y cómo resolverlos
Estos son los tropiezos más habituales al montar la rotación y su solución directa:
| Problema | Solución |
|---|---|
| Todos los proxies reciben CAPTCHA | Cambia a proxies residenciales autorizados; baja la frecuencia |
| Errores de tiempo de espera del proxy | Quita del grupo los proxies lentos; sube el tiempo de espera |
| Contenido distinto según el proxy | Algunos sitios sirven contenido geolocalizado; normaliza la salida |
| El token de CAPTCHA no funciona con el proxy | Asegúrate de usar el token desde la misma sesión/IP |
Buenas prácticas que evitan bloqueos
- Haz coincidir la geografía: usa IP del mismo país que el sitio objetivo.
- Una sesión por proxy: no reutilices una misma sesión entre proxies distintos.
- Limita la frecuencia por IP: entre 5 y 10 solicitudes por minuto como máximo.
- Vigila la tasa de CAPTCHA: registra qué proxies disparan más desafíos y descártalos.
- Mantén sesiones fijas: conserva el mismo proxy en flujos de varios pasos.
- Gestiona los fallos: reintenta con otro proxy ante errores de conexión.
Preguntas frecuentes
¿La rotación de proxies elimina los CAPTCHA por completo?
No. Reduce mucho la frecuencia con la que aparecen, pero algunos sitios los muestran de todas formas. Por eso conviene combinar la rotación con CaptchaAI, que resuelve por API los que se cuelan.
¿Qué tipo de proxy genera menos CAPTCHA?
Los proxies residenciales y móviles disparan menos CAPTCHA porque las IP parecen de usuarios reales; los de centro de datos son más baratos, pero levantan más sospechas en sitios muy protegidos.
¿Debo usar la misma IP para resolver el CAPTCHA y para el scraping?
Depende del tipo. Para la mayoría, el token vale sin importar la IP. Para Cloudflare Challenge sí: la cookie qa_validation_cookie queda ligada a la IP, así que usa el mismo proxy en toda la sesión.
¿Cuánto cuesta resolver los CAPTCHA que aún aparecen?
CaptchaAI cobra por threads en paralelo, no por resolución. El plan BASIC ($15/mes, 5 threads) cubre un scraping moderado con solves ilimitados; escala los threads cuando crezca el volumen.