Si te dedicas al scraping de marketplaces, monitoreo de precios de la competencia o recopilación de datos de sitios web, conoces el problema: los sitios bloquean direcciones IP, requieren captcha o devuelven páginas vacías. El ban rate (porcentaje de solicitudes bloqueadas) puede alcanzar el 70-90%, haciendo imposible el scraping. En este artículo analizaremos métodos concretos que ayudarán a reducir el ban rate al 5-10% y recopilar datos de manera estable.
Examinaremos tanto soluciones técnicas (rotación de proxies, encabezados HTTP, fingerprinting) como patrones de comportamiento (retrasos, imitación de acciones del usuario). Todos los métodos han sido probados en la práctica al hacer scraping de Wildberries, Ozon, Avito y plataformas extranjeras.
Por qué los sitios bloquean scrapers: principales desencadenantes
Antes de analizar los métodos de protección, es importante entender cómo los sitios identifican el tráfico automatizado. Los sistemas anti-bot modernos (Cloudflare, Akamai, DataDome, Imperva) analizan decenas de parámetros de cada solicitud. Estos son los principales desencadenantes de bloqueo:
Desencadenantes a nivel de red:
- Demasiadas solicitudes desde una sola dirección IP (por ejemplo, más de 100 solicitudes por minuto)
- IP de rangos conocidos de centros de datos (AWS, Google Cloud, Hetzner)
- Inconsistencia geográfica: una IP de Rusia solicita la versión en inglés del sitio
- Ausencia de registro DNS inverso para la dirección IP
Desencadenantes a nivel HTTP:
- Ausencia o encabezados HTTP incorrectos (User-Agent, Accept-Language, Referer)
- El orden de los encabezados difiere del estándar del navegador
- La versión TLS/SSL no corresponde al navegador declarado
- Ausencia de cookies o uso incorrecto de las mismas
Desencadenantes a nivel de navegador (JavaScript):
- Ausencia de ejecución de JavaScript (si usas un cliente HTTP simple)
- Browser fingerprinting: Canvas, WebGL, AudioContext, fuentes instaladas
- Ausencia de movimiento del ratón, scroll, clics
- Tamaño de la ventana del navegador (los navegadores headless suelen tener tamaños no estándar)
- Presencia de automatización: propiedades navigator.webdriver, window.chrome
Desencadenantes de comportamiento:
- Navegación demasiado rápida entre páginas (menos de 1 segundo)
- Intervalos idénticos entre solicitudes (por ejemplo, exactamente cada 2 segundos)
- Recorrido secuencial de páginas (1, 2, 3, 4...) sin saltos
- Ausencia de acciones típicas del usuario: búsqueda, filtros, visualización de imágenes
Por ejemplo, al hacer scraping de Wildberries, un error típico es enviar solicitudes cada 0.5 segundos desde una sola IP. El sistema anti-bot Cloudflare identificará instantáneamente el patrón y bloqueará la IP durante 24 horas. Un usuario real tarda 5-15 segundos en ver la ficha de un producto, hace scroll en la página, hace clic en las imágenes.
Rotación de proxies: cómo cambiar correctamente las direcciones IP
El uso de proxies es un método básico para reducir el ban rate. Pero es importante no solo comprar proxies, sino configurar correctamente la rotación. Aquí están las estrategias probadas:
Elección del tipo de proxy para scraping
| Tipo de proxy | Ban rate | Velocidad | Cuándo usar |
|---|---|---|---|
| Proxies de centros de datos | Alto (40-60%) | Muy alta | Sitios simples sin protección, scraping masivo con gran pool de IP |
| Proxies residenciales | Bajo (5-15%) | Media | Marketplaces (Wildberries, Ozon), sitios con Cloudflare, redes sociales |
| Proxies móviles | Muy bajo (2-8%) | Baja | Sitios con protección agresiva, versiones móviles de aplicaciones |
Para el scraping de marketplaces (Wildberries, Ozon, Avito) se recomiendan proxies residenciales: tienen IPs de usuarios domésticos reales que son difíciles de distinguir del tráfico normal. Los proxies de centros de datos son adecuados para sitios menos protegidos o cuando se necesita máxima velocidad con gran volumen de datos.
Estrategias de rotación de direcciones IP
Estrategia 1: Rotación por tiempo
Cambia la IP cada 5-10 minutos. Este es el equilibrio óptimo: suficientemente largo para no levantar sospechas con cambios frecuentes, pero suficientemente frecuente para no acumular historial de solicitudes en una sola IP.
Ejemplo: Al hacer scraping de un catálogo de 1000 productos con un intervalo de 3 segundos entre solicitudes, una IP estará activa aproximadamente 100 solicitudes, luego ocurre el cambio.
Estrategia 2: Rotación por número de solicitudes
Cambia la IP después de 50-150 solicitudes. Esto ayuda a evitar la acumulación de actividad sospechosa en una sola dirección. Añade aleatoriedad: no exactamente 100 solicitudes, sino de 80 a 120.
Ejemplo: Configura el script para que después de un número aleatorio de solicitudes (80-120) ocurra la rotación de proxy del pool.
Estrategia 3: Sticky sessions (proxies de sesión)
Para sitios que requieren autorización o trabajan con carrito de compras, usa sticky sessions: fijación de IP durante la sesión (10-30 minutos). Esto permite mantener las cookies y no levantar sospechas al cambiar de IP dentro de una misma sesión.
Ejemplo: Al hacer scraping del área personal en Ozon, usa una sola IP para el inicio de sesión y todas las solicitudes posteriores dentro de una sesión de 15 minutos.
Importante: No uses la misma IP para diferentes tareas. Si una IP fue bloqueada al hacer scraping de un sitio, no la uses inmediatamente para otro: espera 24-48 horas.
Tamaño del pool de proxies
El tamaño mínimo del pool depende de la intensidad del scraping:
- Baja intensidad (hasta 10,000 solicitudes por día): 10-20 proxies
- Intensidad media (10,000 - 100,000 solicitudes por día): 50-100 proxies
- Alta intensidad (más de 100,000 solicitudes por día): 200+ proxies o residenciales con rotación automática
Para proxies residenciales con rotación en cada solicitud (rotating proxies), el tamaño del pool puede ser menor, ya que el proveedor automáticamente asigna una nueva IP de su pool de millones de direcciones.
User-Agent y encabezados HTTP: imitación de un navegador real
Incluso con buenos proxies, pueden bloquearte si los encabezados HTTP parecen sospechosos. Los sitios analizan no solo el User-Agent, sino también el orden de los encabezados, sus valores y correspondencia entre sí.
User-Agent correcto
No uses el mismo User-Agent para todas las solicitudes. Crea una lista de navegadores populares y elige aleatoriamente de ella:
user_agents = [
# Chrome en Windows
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
# Chrome en macOS
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
# Firefox en Windows
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
# Safari en macOS
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15",
# Edge en Windows
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"
]
Error: Usar versiones obsoletas de navegadores (por ejemplo, Chrome 80) levantará sospechas inmediatamente. Actualiza la lista de User-Agent cada 2-3 meses, siguiendo las versiones actuales en el sitio whatismybrowser.com.
Conjunto completo de encabezados HTTP
Los navegadores modernos envían 15-20 encabezados. Aquí está el conjunto mínimo necesario para imitar Chrome:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "es-ES,es;q=0.9,en-US;q=0.8,en;q=0.7",
"Accept-Encoding": "gzip, deflate, br",
"DNT": "1",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Cache-Control": "max-age=0",
"sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"'
}
Presta atención a los encabezados Sec-Fetch-* y sec-ch-ua-*: aparecieron en las nuevas versiones de Chrome y su ausencia puede delatar la automatización.
El orden de los encabezados importa
Los navegadores envían los encabezados en un orden determinado. Por ejemplo, Chrome siempre coloca Host primero, luego Connection, User-Agent y así sucesivamente. Si usas la biblioteca requests de Python, el orden puede ser alfabético, lo que delatará la automatización.
Solución: usa bibliotecas que formen correctamente los encabezados (curl_cffi para Python, got para Node.js) o navegadores headless (Puppeteer, Playwright, Selenium) que generan encabezados como un navegador real.
Retrasos entre solicitudes: intervalos óptimos
Uno de los métodos más simples pero efectivos para reducir el ban rate son los retrasos correctos entre solicitudes. Un usuario real no puede abrir 10 páginas por segundo, por lo que las solicitudes demasiado rápidas provocan bloqueos instantáneos.
Retrasos aleatorios en lugar de fijos
No uses un retraso fijo (por ejemplo, exactamente 2 segundos entre solicitudes). Los sistemas anti-bot identifican fácilmente este patrón. Usa un intervalo aleatorio:
import random
import time
# En lugar de retraso fijo
time.sleep(2) # ❌ Malo
# Usa un intervalo aleatorio
delay = random.uniform(2.5, 5.5) # ✅ Bueno
time.sleep(delay)
Intervalos recomendados para diferentes sitios
| Tipo de sitio | Retraso mínimo | Retraso recomendado | Ejemplos |
|---|---|---|---|
| Marketplaces con protección | 3-5 seg | 5-10 seg | Wildberries, Ozon, Lamoda |
| Tablones de anuncios | 2-4 seg | 4-8 seg | Avito, Yula, CIAN |
| Sitios de noticias | 1-2 seg | 2-4 seg | RBC, Kommersant, Vedomosti |
| API sin restricciones | 0.5-1 seg | 1-2 seg | APIs abiertas, feeds RSS |
Retrasos adaptativos basados en respuestas del servidor
Un enfoque avanzado es cambiar dinámicamente los retrasos según las respuestas del servidor:
base_delay = 3.0 # Retraso base
delay_multiplier = 1.0
response = requests.get(url, headers=headers, proxies=proxies)
# Si recibimos captcha o 429, aumentamos el retraso
if response.status_code == 429 or 'captcha' in response.text.lower():
delay_multiplier *= 1.5
print(f"Protección detectada, aumentando retraso a {base_delay * delay_multiplier}s")
# Si todo está bien, podemos acelerar un poco
elif response.status_code == 200:
delay_multiplier = max(1.0, delay_multiplier * 0.95)
time.sleep(random.uniform(base_delay * delay_multiplier, base_delay * delay_multiplier * 1.5))
Este enfoque permite ralentizar automáticamente al detectar protección y acelerar cuando el sitio no muestra agresividad.
Protección contra fingerprinting: Canvas, WebGL, fuentes
Si el sitio usa JavaScript para verificación, los simples encabezados HTTP no son suficientes. Los sistemas anti-bot modernos crean una "huella digital" del navegador (fingerprint) basada en decenas de parámetros: Canvas, WebGL, fuentes instaladas, zona horaria, resolución de pantalla y otros.
Parámetros principales del fingerprinting
Canvas fingerprinting
El sitio dibuja una imagen invisible en Canvas y la lee. Diferentes navegadores y sistemas operativos renderizan la imagen de manera diferente, creando una huella única. Los navegadores headless a menudo generan el mismo Canvas, lo que delata la automatización.
WebGL fingerprinting
Similar a Canvas, pero usa renderizado 3D. Se lee información sobre la tarjeta gráfica, controladores, extensiones soportadas. Los navegadores headless a menudo muestran renderizado por software (SwiftShader) en lugar de GPU real.
Fuentes instaladas
JavaScript puede determinar la lista de fuentes instaladas. Los navegadores headless suelen tener un conjunto mínimo de fuentes del sistema, lo que difiere de un usuario real con Microsoft Office, Adobe y otros programas instalados.
Propiedades de Navigator
Las propiedades navigator.webdriver, navigator.plugins, navigator.languages delatan la automatización. Por ejemplo, en Selenium navigator.webdriver === true, lo que es detectado instantáneamente por los sistemas anti-bot.
Herramientas para bypass de fingerprinting
Para el bypass de fingerprinting usa herramientas especializadas:
- Undetected ChromeDriver (Python): versión modificada de Selenium que oculta signos de automatización
- Puppeteer Stealth (Node.js): plugin para Puppeteer que sustituye parámetros de fingerprint
- Playwright con stealth: similar a Puppeteer, pero con mejor soporte de diferentes navegadores
- Navegadores antidetección (Dolphin Anty, AdsPower, Multilogin): para quienes no quieren escribir código, estos navegadores sustituyen automáticamente el fingerprint
Ejemplo de uso de undetected-chromedriver en Python:
import undetected_chromedriver as uc
# Creamos navegador con protección contra detección
options = uc.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
driver = uc.Chrome(options=options)
driver.get('https://example.com')
# Verificamos que navigator.webdriver === undefined
webdriver_status = driver.execute_script("return navigator.webdriver")
print(f"navigator.webdriver: {webdriver_status}") # Debe ser None/undefined
Gestión de cookies y sesiones
Muchos sitios usan cookies para rastrear el comportamiento de los usuarios. La gestión correcta de cookies ayuda a evitar bloqueos y parecer un usuario real.
Guardar y reutilizar cookies
En lugar de crear una nueva sesión en cada solicitud, guarda las cookies y reutilízalas. Esto imita el comportamiento de un usuario real que regresa al sitio:
import requests
import pickle
session = requests.Session()
# Primera visita: obtenemos cookies
response = session.get('https://example.com')
# Guardamos cookies en archivo
with open('cookies.pkl', 'wb') as f:
pickle.dump(session.cookies, f)
# Más tarde cargamos cookies
with open('cookies.pkl', 'rb') as f:
session.cookies.update(pickle.load(f))
# Ahora las solicitudes parecen de un usuario que regresa
response = session.get('https://example.com/catalog')
Calentamiento de sesión antes del scraping
No comiences el scraping directamente en las páginas objetivo. Imita el comportamiento de un usuario real:
- Abre la página principal del sitio
- Espera 2-5 segundos
- Abre la página de categoría o sección
- Espera 3-7 segundos
- Solo después de esto comienza a hacer scraping de las páginas objetivo
Esto crea un historial de actividad en las cookies y reduce la probabilidad de bloqueo.
Manejo de session cookies y tokens
Algunos sitios generan tokens únicos en la primera visita y los verifican en solicitudes posteriores. Por ejemplo, Wildberries usa un token en el encabezado x-requested-with. Siempre guarda estos tokens de la primera respuesta y envíalos en solicitudes posteriores.
Renderizado de JavaScript: cuándo es necesario
Muchos sitios modernos cargan contenido a través de JavaScript. Si usas un cliente HTTP simple (requests en Python, axios en Node.js), obtendrás una página vacía o un placeholder. En estos casos es necesario el renderizado de JavaScript.
Cuándo se necesita renderizado de JavaScript
- El sitio usa React, Vue, Angular: el contenido se carga después de la carga inicial de la página
- Los datos se cargan mediante solicitudes AJAX/Fetch
- El sitio requiere ejecución de JavaScript para generar tokens o cookies
- Hay protección contra bots que requiere ejecución de código JS (por ejemplo, Cloudflare Challenge)
Herramientas para renderizado de JavaScript
| Herramienta | Lenguaje | Velocidad | Bypass de protección |
|---|---|---|---|
| Selenium | Python, Java, C# | Lenta | Medio (con undetected-chromedriver) |
| Puppeteer | Node.js | Media | Bueno (con puppeteer-extra-plugin-stealth) |
| Playwright | Python, Node.js, Java | Rápida | Excelente |
| Splash | HTTP API | Media | Débil |
Para la mayoría de las tareas se recomienda Playwright: es más rápido que Selenium, mejor para bypass de protección y tiene una API más conveniente.
Alternativa: interceptar solicitudes API
A menudo se puede evitar el renderizado de JavaScript si encuentras las solicitudes API que el sitio usa para cargar datos. Abre DevTools (F12) → pestaña Network → filtro XHR/Fetch y mira qué solicitudes envía el sitio. Luego repite estas solicitudes directamente a través del cliente HTTP.
Ejemplo: Wildberries carga datos de productos a través de la API https://catalog.wb.ru/catalog/.... En lugar de renderizar toda la página, puedes solicitar esta API directamente, lo que es 10-20 veces más rápido.
Bypass de captcha: soluciones automáticas
Incluso con proxies y encabezados correctos puedes encontrarte con captcha. Existen varios enfoques para resolverla:
Tipos de captcha y métodos de resolución
reCAPTCHA v2 (casilla "No soy un robot")
Se resuelve mediante servicios de reconocimiento: 2Captcha, Anti-Captcha, CapMonster. Costo: $1-3 por 1000 resoluciones. Tiempo de resolución: 10-30 segundos.
reCAPTCHA v3 (invisible, basada en puntuación)
Más compleja. Analiza el comportamiento del usuario y asigna una puntuación de 0 a 1. Bypass: uso de navegadores headless con fingerprint correcto + imitación de acciones del usuario (movimiento del ratón, clics).
hCaptcha
Análogo a reCAPTCHA, usado en muchos sitios. Se resuelve mediante los mismos servicios de reconocimiento. Costo: $0.5-2 por 1000 resoluciones.
Cloudflare Challenge
JavaScript-challenge que verifica el navegador. Bypass: uso de bibliotecas especializadas (cloudscraper para Python, cloudflare-scraper para Node.js) o servicios (FlareSolverr).
Integración de servicio de reconocimiento de captcha
Ejemplo de integración de 2Captcha en Python:
from twocaptcha import TwoCaptcha
solver = TwoCaptcha('YOUR_API_KEY')
try:
# Resolvemos reCAPTCHA v2
result = solver.recaptcha(
sitekey='6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
url='https://example.com'
)
# Obtenemos token de resolución
captcha_token = result['code']
# Enviamos formulario con token
response = requests.post('https://example.com/submit', data={
'g-recaptcha-response': captcha_token
})
except Exception as e:
print(f"Error al resolver captcha: {e}")
Importante: Resolver captcha ralentiza el scraping 10-30 veces y aumenta el costo. Úsalo solo cuando otros métodos no funcionen. Primero intenta mejorar los proxies, fingerprint y retrasos.
Rate limiting: cómo no exceder los límites del sitio
Muchos sitios tienen límites explícitos o implícitos en el número de solicitudes. Exceder estos límites lleva a bloqueo temporal o permanente de la IP.
Determinación de límites del sitio
Presta atención a los encabezados HTTP en las respuestas del servidor:
X-RateLimit-Limit: número máximo de solicitudes en el períodoX-RateLimit-Remaining: cuántas solicitudes quedanX-RateLimit-Reset: cuándo se restablecerá el límite (Unix timestamp)Retry-After: en cuántos segundos se puede repetir la solicitud
Si recibes el código de estado 429 (Too Many Requests), significa que se excedió el límite. Lee el encabezado Retry-After y espera el tiempo indicado antes de la siguiente solicitud.
Implementación de rate limiter
Crea un mecanismo de control de velocidad de solicitudes: