Has adquirido una IP residencial costosa, configurado la rotación, insertado un User-Agent realista, pero el parser aún termina en un captcha o recibe una respuesta vacía. El problema casi siempre no está en la IP, sino en la huella TLS: la biblioteca que estás utilizando para enviar la solicitud HTTPS "suena" diferente a un navegador real. Los sistemas anti-bots de Wildberries, Ozon, Cloudflare y Akamai lo detectan antes de verificar tu dirección IP.
Qué es la huella TLS y por qué es más importante que la IP
Cuando un cliente establece una conexión HTTPS, envía al servidor un paquete ClientHello — parte del handshake TLS. Este paquete contiene una lista cifrada de las versiones TLS soportadas, conjuntos de cifrado (cipher suites), el orden de las extensiones (extensions), curvas elípticas y algoritmos de compresión. Este conjunto de parámetros es único para cada combinación de "biblioteca + sistema operativo + versión del stack TLS".
Chrome, Firefox y Safari forman el ClientHello a su manera, y este conjunto prácticamente no cambia de una solicitud a otra — a diferencia de la IP o el User-Agent, que son fáciles de falsificar. Sin embargo, las bibliotecas HTTP estándar — requests, urllib3, el HttpClient estándar en Java, el stack TLS integrado de Node.js — generan un ClientHello completamente diferente, porque utilizan OpenSSL u otra biblioteca de manera diferente a un navegador.
Es por eso que puedes conectar una IP residencial "limpia", insertar un User-Agent fresco de un Chrome real — y aún así recibir un bloqueo. El servidor ve la IP del usuario de una casa residencial, ve el encabezado "Chrome 124", pero el handshake TLS dice: "esto es un script de Python". La discrepancia es una señal clara para el anti-bot.
Cómo los sistemas anti-bots detectan el parser por JA3/JA4
Para convertir los parámetros del ClientHello en un identificador compacto, se utiliza el algoritmo JA3 (y su versión más nueva JA4). Este toma la versión TLS, la lista de cifrados, las extensiones y las curvas, los concatena en una cadena y los hash a través de MD5. El resultado es un hash corto del tipo 769,47-53-5-10...,0-23-65281...,29-23-24,0, que identifica de manera única la "huella" del cliente.
Los proveedores de anti-bots (Cloudflare, Akamai, PerimeterX, DataDome — y sus análogos que utilizan Wildberries y Ozon) mantienen bases de datos de hashes JA3/JA4 conocidos de bibliotecas HTTP populares: requests, aiohttp, Scrapy, Node fetch, Java HttpClient, Go net/http. Si el hash coincide con una firma conocida de "script", y no con la firma de Chrome/Firefox/Safari — la solicitud se marca como sospechosa incluso antes de analizar el comportamiento.
Luego, el sistema observa la coincidencia de la huella TLS con el User-Agent declarado. Si en los encabezados dice "Chrome 124 en Windows", y la huella TLS corresponde a OpenSSL 1.1.1 de la biblioteca estándar de Python — esto se llama desajuste TLS/HTTP, una de las señales más confiables de detección de automatización. Así es como se detectan los parsers incluso con una IP residencial ideal y encabezados correctos.
Cómo verificar tu huella TLS: herramientas
Antes de solucionar el problema, necesitas ver lo que ve el servidor. Hay varios servicios públicos que muestran tu hash JA3/JA4 y el conjunto completo de parámetros del ClientHello:
- tls.peet.ws — muestra JA3, JA4, la lista de cifrados y extensiones en formato JSON, conveniente para la verificación automática por script.
- ja3er.com — base de datos de hashes JA3 conocidos vinculados a bibliotecas y navegadores específicos.
- browserleaks.com/tls — comparación visual de tu huella con las típicas de navegadores.
- Wireshark localmente — si deseas ver el paquete bruto ClientHello al enviar una solicitud desde tu script.
La prueba práctica es simple: abre tls.peet.ws en un Chrome normal y anota el hash JA4. Luego envía una solicitud GET a la misma dirección desde tu parser (a través de requests, curl_cffi o cualquier otra biblioteca) a través del mismo proxy y compara los hashes. Si son diferentes — el servidor ve la diferencia entre "navegador" y "script" en cada solicitud, sin importar cuán limpia sea la IP.
Verificación en Python: requests, httpx, curl_cffi
Vamos a analizar en la práctica por qué las bibliotecas estándar de Python delatan al parser. Una solicitud común a través de requests:
import requests
resp = requests.get("https://tls.peet.ws/api/all", proxies={
"https": "http://user:pass@proxy_host:port"
})
print(resp.json()["tls"]["ja4"])
# El resultado será diferente al JA4 de un Chrome real,
# ya que requests utiliza el módulo ssl estándar de Python
El problema es que requests y httpx utilizan OpenSSL del sistema a través del módulo ssl, y el orden y conjunto de extensiones TLS están fijos y no coinciden con Chrome/Firefox. La solución es la biblioteca curl_cffi, que utiliza curl parcheado con perfiles TLS reales de navegadores:
from curl_cffi import requests as cffi_requests
resp = cffi_requests.get(
"https://tls.peet.ws/api/all",
impersonate="chrome124",
proxies={"https": "http://user:pass@proxy_host:port"}
)
print(resp.json()["tls"]["ja4"])
# El hash será idéntico al de un Chrome 124 real en escritorio
El parámetro impersonate hace que curl_cffi reproduzca no solo el ClientHello, sino también el orden de los encabezados HTTP/2 (frame order), que también forma parte de la huella. Un enfoque similar es utilizado por las bibliotecas tls-client para Go y undetected-chromedriver para aquellos que parsean a través de un navegador real y no a través de un cliente HTTP.
Si el parsing se realiza a través de un navegador sin cabeza (Playwright, Puppeteer, Selenium), la huella TLS se forma por el motor Chromium/Firefox y por defecto coincide con el navegador real. Pero aquí surge otro problema: las firmas de automatización a nivel de JS (flags de webdriver, canvas fingerprint), por lo que para escenarios sin cabeza también se necesitan parches como playwright-stealth.
TLS + HTTP/2 + encabezados: por qué la combinación es importante
La huella TLS es solo una capa de detección. Los sistemas anti-bots comparan varios niveles simultáneamente:
- TLS ClientHello (JA3/JA4) — conjunto de cifrados y extensiones.
- Huella HTTP/2 — orden de los pseudo-encabezados (:method, :path, :authority), configuraciones del frame SETTINGS, tamaño de la ventana.
- Encabezados HTTP — orden y conjunto de encabezados comunes (Accept-Language, Sec-Ch-Ua, Sec-Fetch-*).
- User-Agent — debe coincidir con la versión del perfil TLS: si el UA dice "Chrome 124", y el TLS corresponde a Chrome 110, esto también es sospechoso.
Un error común es actualizar el User-Agent a la última versión de Chrome, olvidando actualizar el perfil TLS en curl_cffi u otra biblioteca. Esta discrepancia de versiones es tan clara para el anti-bot como la completa falta de camuflaje. Verifica que la versión impersonate y la versión en el User-Agent coincidan, y actualiza ambos parámetros de forma sincrónica al salir nuevas versiones del navegador.
Otro aspecto es el orden de los encabezados. El navegador envía los encabezados en un orden estrictamente definido, mientras que muchas bibliotecas HTTP los ordenan alfabéticamente o según el orden de adición en el código. Incluso si el conjunto de encabezados es idéntico al del navegador, un orden incorrecto es una señal adicional para sistemas anti-bots avanzados como DataDome.
El papel de los proxies: por qué una IP limpia no es suficiente
La IP residencial resuelve una tarea específica — reduce la sospecha por geografía, ASN y reputación de la dirección. Las IP de centros de datos a menudo están en listas negras, porque desde ellas se genera tráfico automatizado masivo, mientras que las residenciales pertenecen a proveedores reales y usuarios comunes. Para el parsing de Wildberries, Ozon o Avito, esto es crítico: sin una IP limpia, la solicitud se bloquea solo por este criterio, sin verificar siquiera el TLS.
Pero la IP y la huella TLS son dos capas de protección independientes, y resuelven problemas diferentes. La IP le dice al servidor "de dónde" proviene la solicitud, la huella TLS le dice "con qué" fue enviada. Por lo tanto, la combinación de una IP limpia y un perfil TLS correcto es el conjunto mínimo para un parsing estable. Para tareas con alta frecuencia de solicitudes y un anti-bot agresivo, es mejor utilizar proxies residenciales, que ofrecen un bajo porcentaje de bloqueos por reputación de IP, pero asegúrate de combinarlos con una biblioteca que reproduzca correctamente el perfil TLS de un navegador real.
Para el monitoreo de precios en marketplaces, donde la velocidad y el volumen de solicitudes son importantes, a menudo se utilizan proxies de centros de datos en combinación con enmascaramiento TLS a través de curl_cffi — esto es más barato que los residenciales y es bastante efectivo si el sistema anti-bots del sitio no es demasiado agresivo. Y para tareas donde el sitio verifica activamente las redes móviles (por ejemplo, parsing de versiones móviles de aplicaciones a través de API), se utilizan proxies móviles — que ofrecen un nivel adicional de confianza gracias a la reputación de las redes operadoras.
Lista de verificación para configurar el parser sin detección
Reúne la verificación en un solo proceso antes de lanzar el parser en producción:
- Mide el hash JA4 de tu script a través de tls.peet.ws y compáralo con un navegador real de la misma versión.
- Utiliza una biblioteca con soporte para impersonación TLS: curl_cffi (Python), tls-client (Go), CycleTLS (Node.js).
- Sincroniza la versión del perfil TLS (impersonate) con la versión en el User-Agent.
- Verifica el orden de los encabezados HTTP — debe coincidir con el navegador real, no con el alfabético.
- Conecta una IP residencial o móvil limpia según la geografía de tu tarea.
- Configura la rotación de IP por separado del perfil TLS — no los vincules rígidamente.
- Actualiza regularmente el perfil TLS al salir nuevas versiones de Chrome — las firmas antiguas entran en las bases de datos de anti-bots más rápido de lo que parece.
- Para escenarios con verificaciones de JS (Cloudflare Challenge), utiliza un navegador sin cabeza con parches stealth en lugar de un cliente HTTP limpio.
Comparación de bibliotecas y herramientas
| Herramienta | Huella TLS del navegador | Velocidad | Cuándo usar |
|---|---|---|---|
| requests / httpx | No, devuelve script | Alta | Sitios sin detección TLS, APIs internas |
| curl_cffi | Sí, copia exacta | Alta | Marketplaces, anti-bot Cloudflare/Akamai |
| tls-client (Go) | Sí | Muy alta | Carga alta, parsing masivo |
| Playwright / Puppeteer | Sí, motor real | Baja | Renderizado JS, Cloudflare Challenge, SPA complejas |
| Scrapy (estándar) | No | Alta | Sitios sin protección anti-bots estricta |
Conclusión
La huella TLS es una capa de protección que muchos parsers ignoran por completo, gastando recursos en encontrar la IP y User-Agent perfectos, pero olvidando que la estructura misma del handshake TLS revela la automatización antes de que el servidor mire los encabezados. La solución es utilizar bibliotecas con soporte para impersonación TLS (curl_cffi, tls-client), sincronizar la versión del perfil con el User-Agent y verificar el hash JA4 final antes de lanzar a gran escala.
La IP sigue siendo un factor importante — sin una dirección limpia, incluso la huella TLS perfecta no ayudará a evitar el bloqueo por reputación de la red. Para el parsing de marketplaces y monitoreo de precios, es razonable combinar la configuración TLS correcta con proxies residenciales — esta combinación cubre ambas capas de detección y reduce notablemente el porcentaje de bloqueos en largas sesiones de parsing.