Si alguna vez te has encontrado manteniendo dos codebases paralelos —uno con requests para peticiones rápidas y otro con Selenium o Playwright para páginas renderizadas en JavaScript— sabes lo frustrante que es sincronizar cookies, headers y sesiones de proxy entre ambos. DrissionPage resuelve exactamente ese problema: es un framework Python que unifica el estilo requests con el control de Chromium vía CDP, permitiendo alternar entre modo HTTP y modo navegador sin perder estado. En esta guía práctica de DrissionPage veremos cómo integrar proxies residenciales de ProxyHat de forma idiomática, cuándo escalar a navegador y cuándo quedarse en HTTP para ahorrar costes.
Aviso legal y ético: Esta guía asume que extraes datos públicos, respetas
robots.txt, los términos de servicio de cada sitio y normativas como el GDPR europeo y la CFAA estadounidense. El scraping de datos privados, tras login sin autorización o con intención de causar daño puede ser ilegal. Prefiere siempre APIs oficiales cuando existan.
Qué es DrissionPage y por qué importa para usuarios de proxy
DrissionPage es un framework de automatización web en Python que combina dos motores en una sola API:
- SessionPage: usa
requestspor debajo para peticiones HTTP rápidas, sin navegador. Ideal para APIs JSON, HTML estático y endpoints públicos. - ChromiumPage: controla un navegador real Chromium vía Chrome DevTools Protocol (CDP), sin necesidad de un driver externo como ChromeDriver. Soporta JavaScript, captura de paquetes y interacción completa.
- WebPage: envuelve ambos modos y permite cambiar entre HTTP y navegador manteniendo cookies, headers y sesión de proxy compartida.
Para quien hace drissionpage web scraping, la ventaja clave es el coste: ejecutar un navegador headless consume entre 300 MB y 500 MB de RAM por instancia, mientras que una petición HTTP con SessionPage usa menos de 20 MB. Si el 80% de tu flujo puede resolverse en modo HTTP, puedes reducir tu infraestructura de scraping en un factor de 5x o más. Y cuando necesitas renderizar JavaScript, escalas a ChromiumPage sin reescribir código ni perder la sesión de proxy.
Para usuarios de proxy, esto significa que puedes mantener una sesión residencial pegada (sticky session) a través de ambos modos: el mismo IP de salida se usa tanto en la petición HTTP inicial como en la sesión de navegador posterior, lo que es crítico para sitios que correlacionan IPs entre requests y carga de recursos del navegador.
Contexto técnico: por qué existe este problema
Los sitios modernos mezclan contenido estático con aplicaciones JavaScript pesadas. Un scraper típico se enfrenta a tres escenarios en el mismo dominio:
- Páginas de listado servidas como HTML estático — rápidas de extraer con HTTP.
- Endpoints AJAX que devuelven JSON — accesibles directamente con HTTP si conoces la URL.
- Páginas de detalle que requieren ejecución de JavaScript para renderizar contenido — necesitan navegador.
El enfoque tradicional es usar dos herramientas: requests para los casos 1 y 2, y Selenium/Playwright para el caso 3. El problema es que cada herramienta mantiene su propio pool de cookies, su propia configuración de proxy y sus propios headers. Cuando un sitio requiere que la cookie de sesión del listado coincida con la del detalle renderizado, te ves forzado a copiar cookies manualmente entre herramientas, lo que es propenso a errores y pierde la afinidad de IP.
DrissionPage elimina este problema porque WebPage comparte el objeto de sesión subyacente. Al cambiar de modo HTTP a modo navegador con page.change_mode(), las cookies y los headers se transfieren automáticamente. Y si configuraste un proxy al crear la página, ese proxy persiste en ambos modos.
API idiomática de DrissionPage: locators, opciones y captura de paquetes
Localización de elementos con ele() y eles()
DrissionPage usa una sintaxis de localización propia que es más legible que XPath puro. Los selectores más comunes son:
page.ele('#id')— por ID.page.ele('@class=price')— por atributo.page.ele('tag:input')— por etiqueta.page.ele('xpath://div[@class="product"]')— XPath cuando lo necesitas.page.eles('@class=item')— plural, devuelve una lista.
La función ele() devuelve el primer match; eles() devuelve todos. Ambas aceptan encadenamiento: page.ele('tag:form').ele('@name=email').
ChromiumOptions: configuración del navegador
Para configurar el navegador Chromium, DrissionPage expone ChromiumOptions, donde puedes definir argumentos de línea de comandos, ruta del binario, modo headless y, lo que nos ocupa, el proxy:
from DrissionPage import ChromiumOptions
co = ChromiumOptions()
co.set_argument('--headless=new')
co.set_argument('--no-sandbox')
co.set_argument('--disable-gpu')
co.set_proxy('http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080')
listen.start(): captura de XHR y JSON en segundo plano
Una de las funcionalidades más potentes de DrissionPage con ChromiumPage es listen, que intercepta tráfico de red del navegador en tiempo real. Esto te permite descubrir APIs ocultas que el frontend llama vía XHR sin necesidad de inspeccionar manualmente DevTools:
from DrissionPage import ChromiumPage
page = ChromiumPage()
page.listen.start('api/products') # filtra URLs que contengan este patrón
page.get('https://example.com/catalog')
for packet in page.listen.steps(count=3):
print(packet.url, packet.response.body)
Cada packet expone url, method, request.body, response.body y response.headers. Si el sitio carga datos de producto vía un endpoint JSON, lo capturas directamente sin parsear el DOM renderizado.
Configuración de proxy en DrissionPage: SessionPage vs ChromiumPage
La configuración de proxy difiere según el modo. Aquí es donde entra el drissionpage proxy como pieza central de tu infraestructura de scraping.
Proxy en SessionPage (modo HTTP)
SessionPage acepta proxies mediante set_proxies(), que internamente configura el diccionario de proxies de requests:
from DrissionPage import SessionPage
page = SessionPage()
page.set.proxies('http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080')
page.get('https://httpbin.org/ip')
print(page.html)
Proxy en ChromiumPage (modo navegador)
Para ChromiumPage, el proxy se configura vía ChromiumOptions.set_proxy() antes de lanzar el navegador. Chromium aplica el proxy a nivel de proceso, por lo que todas las conexiones —documentos, XHR, WebSocket, fuentes— pasan por el mismo endpoint:
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.set_proxy('http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080')
page = ChromiumPage(co)
page.get('https://httpbin.org/ip')
print(page.ele('tag:body').text)
Por qué proxies residenciales para DrissionPage
Los sitios con anti-bot avanzado (Cloudflare, DataDome, PerimeterX) detectan IPs de datacenter con una precisión superior al 90% usando bases de datos ASN como las de MaxMind. Un proxy de datacenter puede ser bloqueado antes de que el navegador termine de cargar. Los proxies residenciales usan IPs asignados a ISP reales, lo que reduce drásticamente la tasa de bloqueo.
Para drissionpage chromium, esto es especialmente importante porque el navegador genera un fingerprint completo: canvas, WebGL, User-Agent, Accept-Language, timezone. Si el IP es de datacenter pero el navegador simula un usuario residencial, la inconsistencia es detectable. Usar un proxy residencial coherente con la geolocalización del navegador es la combinación óptima.
| Tipo de proxy | Coste relativo | Tasa de bloqueo típica | Ideal para |
|---|---|---|---|
| Datacenter | Bajo ($0.5–$1/GB) | 40–80% | APIs públicas, sitios sin anti-bot |
| Residencial | Medio ($2–$8/GB) | 5–15% | SERP, e-commerce, sitios con Cloudflare |
| Móvil | Alto ($5–$15/GB) | 2–8% | Redes sociales, apps móviles |
Ejemplo completo: WebPage con proxy residencial y escalado a Chromium
A continuación, un ejemplo runnable que demuestra el flujo híbrido: empieza en modo HTTP con un proxy residencial de EE.UU., captura datos de un listado estático, y luego escala a modo Chromium para renderizar una página de detalle que requiere JavaScript.
from DrissionPage import WebPage
import json, time, hashlib
def build_username(country='US', session_id=None):
"""Construye el username de ProxyHat con geo-targeting y sesión pegada."""
parts = [f'country-{country}']
if session_id:
parts.append(f'session-{session_id}')
return '-'.join(parts)
# Configuración del proxy residencial
username = build_username(country='US', session_id='order-abc123')
password = 'tu_password'
proxy_url = f'http://{username}:{password}@gate.proxyhat.com:8080'
# Crear WebPage en modo HTTP por defecto
page = WebPage(mode='s') # 's' = SessionPage
page.set.proxies(proxy_url)
# Paso 1: obtener listado en HTTP (rápido, sin navegador)
page.get('https://example.com/api/products?page=1')
data = page.json # DrissionPage parsea JSON automáticamente
product_urls = [item['url'] for item in data.get('products', [])]
print(f'Encontrados {len(product_urls)} productos')
# Paso 2: escalar a Chromium para detalle renderizado
page.change_mode(mode='c') # 'c' = ChromiumPage
# El proxy y las cookies se transfieren automáticamente
for url in product_urls[:5]:
page.get(url)
# Esperar a que el precio dinámico cargue
price_el = page.ele('@class=price', timeout=10)
if price_el:
print(f'{url} -> {price_el.text}')
time.sleep(2) # rate limiting respetuoso
page.close()
Este patrón es la esencia del drissionpage tutorial productivo: usar HTTP para lo que es rápido y escalar a navegador solo cuando es necesario. La sesión pegada (session-order-abc123) garantiza que el mismo IP residencial se use en ambas fases, lo que evita que el sitio detecte un cambio sospechoso de IP entre el listado y el detalle.
Patrones de producción: sesiones, reintentos y concurrencia
Pin de sesión por tarea
Cada tarea de scraping debe tener su propio session_id para mantener un IP estable durante toda la sesión. Si rotas IPs en cada petición dentro de la misma tarea, los sitios con detección de anomalías lo marcan como comportamiento de bot:
import uuid
def scrape_product(product_id):
session = str(uuid.uuid4())[:8]
username = f'user-country-US-session-{session}'
proxy = f'http://{username}:pass@gate.proxyhat.com:8080'
page = WebPage(mode='s')
page.set.proxies(proxy)
try:
page.get(f'https://example.com/product/{product_id}')
if page.status_code != 200:
return None
return page.json
finally:
page.close()
Reintentos con backoff exponencial
Cuando recibes un 403 o un desafío CAPTCHA, lo correcto es retroceder y reintentar con una nueva sesión de proxy, no bombardear el mismo endpoint:
import time, random
def fetch_with_retry(url, max_retries=3):
for attempt in range(max_retries):
session = str(uuid.uuid4())[:8]
proxy = f'http://user-country-US-session-{session}:pass@gate.proxyhat.com:8080'
page = WebPage(mode='s')
page.set.proxies(proxy)
try:
page.get(url, timeout=15)
if page.status_code == 200:
return page
elif page.status_code == 403:
# Bloqueo: esperar y reintentar con nuevo IP
time.sleep(2 ** attempt + random.uniform(0, 1))
else:
time.sleep(1)
except Exception as e:
print(f'Intento {attempt+1} fallido: {e}')
finally:
page.close()
return None
Descubrimiento de APIs ocultas con listen
Uno de los patrones más eficientes es usar listen para descubrir endpoints JSON que el frontend carga vía XHR. Si capturas la URL y los parámetros de la petición, puedes luego llamar ese endpoint directamente con SessionPage en HTTP, evitando el coste del navegador para las páginas restantes:
from DrissionPage import ChromiumPage, ChromiumOptions
def discover_api(url, pattern='api/', timeout=15):
co = ChromiumOptions()
co.set_argument('--headless=new')
co.set_proxy('http://user-country-US:pass@gate.proxyhat.com:8080')
page = ChromiumPage(co)
page.listen.start(pattern)
page.get(url)
api_endpoints = []
for packet in page.listen.steps(timeout=timeout):
if packet.method == 'GET' and packet.response.status == 200:
api_endpoints.append({
'url': packet.url,
'body': packet.response.body[:500] # preview
})
page.listen.stop()
page.close()
return api_endpoints
Límites de concurrencia
DrissionPage no es async nativo, por lo que la concurrencia se maneja con hilos o procesos. Para ChromiumPage, cada instancia consume 300–500 MB de RAM, por lo que en una máquina de 8 GB no deberías correr más de 10–12 navegadores simultáneos. Para SessionPage, el límite es la conexión: puedes manejar 50–100 sesiones concurrentes con un pool de conexiones de requests.
Usa concurrent.futures.ThreadPoolExecutor con un max_workers conservador y un semáforo para limitar la tasa global:
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
rate_limiter = threading.Semaphore(10) # máx 10 peticiones simultáneas
def scrape_with_limit(url):
with rate_limiter:
return fetch_with_retry(url)
urls = ['https://example.com/product/1', 'https://example.com/product/2']
with ThreadPoolExecutor(max_workers=8) as executor:
futures = [executor.submit(scrape_with_limit, url) for url in urls]
for f in as_completed(futures):
result = f.result()
if result:
process(result)
Cuándo NO escalar a navegador
La tentación de usar ChromiumPage para todo es real, pero es casi siempre un error de coste. Escala a navegador solo cuando:
- El contenido requiere ejecución de JavaScript para renderizarse (SPA con React/Vue).
- El sitio usa desafíos anti-bot que requieren interacción real del navegador (no solo headers).
- Necesitas capturar XHR en tiempo real para descubrir APIs ocultas.
- Hay interacción con formularios o clicks necesarios para avanzar.
No escales a navegador cuando:
- El HTML estático ya contiene los datos — usa SessionPage y parsea con
page.ele(). - Conoces el endpoint JSON — llama directamente con SessionPage.
- El sitio tiene una API oficial — úsala en lugar de scrapear.
- Solo necesitas headers o metadata — HTTP es suficiente.
Como regla general, si SessionPage obtiene los datos en menos de 500 ms, no hay razón para lanzar un navegador que tardará 3–5 segundos en cargar.
Configuración de ProxyHat con DrissionPage
Para integrar ProxyHat con DrissionPage de forma idiomática, los pasos son:
- Crea tu cuenta en dashboard.proxyhat.com y obtén tus credenciales.
- Construye el username con flags de geo-targeting y sesión según tus necesidades.
- Configura el proxy en SessionPage con
set.proxies()o en ChromiumOptions conset_proxy(). - Usa sesiones pegadas (
session-xxx) para mantener el mismo IP durante toda la tarea. - Revisa la documentación de ProxyHat para detalles de formato de username.
El gateway de ProxyHat usa el host gate.proxyhat.com con puerto 8080 para HTTP y 1080 para SOCKS5. Para SOCKS5 en ChromiumPage, usa el esqueta socks5://:
co.set_proxy('socks5://user-country-US-session-abc123:pass@gate.proxyhat.com:1080')
Puedes consultar las ubicaciones disponibles y los planes de precios para elegir el tipo de proxy adecuado a tu volumen. Para casos de uso específicos, revisa nuestras guías de web scraping y SERP tracking.
Key Takeaways
- DrissionPage unifica HTTP y navegador en una sola API, compartiendo cookies, headers y proxy entre modos.
- SessionPage es 10x más barato en RAM que ChromiumPage — úsalo por defecto y escala a navegador solo cuando el JS lo requiera.
- ProxyHat residencial con sesiones pegadas (
session-xxx) mantiene el mismo IP entre modo HTTP y modo navegador, evitando detección. - listen.start() permite descubrir APIs JSON ocultas y luego llamarlas directamente con SessionPage.
- Limita la concurrencia: 10–12 navegadores en 8 GB de RAM; 50–100 sesiones HTTP concurrentes.
- Escala a ChromiumPage solo cuando el contenido requiera JS, haya desafíos anti-bot o necesites capturar XHR.
FAQ
¿Qué es DrissionPage?
DrissionPage es un framework Python de automatización web que combina peticiones HTTP estilo requests (SessionPage) con control de Chromium vía CDP (ChromiumPage) en una sola API. La clase WebPage permite alternar entre ambos modos manteniendo cookies, headers y sesión de proxy compartida, lo que reduce costes frente a usar siempre un navegador.
¿Por qué DrissionPage importa para usuarios de proxy?
Porque la sesión de proxy persiste al cambiar entre modo HTTP y modo navegador. Si usas un proxy residencial con sesión pegada, el mismo IP se usa tanto en la petición HTTP como en la sesión de Chromium posterior. Esto evita que el sitio detecte un cambio de IP sospechoso entre fases del scraping, lo que es una causa común de bloqueo.
¿Qué tipo de proxy funciona mejor con DrissionPage?
Los proxies residenciales son los más efectivos para sitios con anti-bot avanzado, porque usan IPs de ISP reales que no son detectados como datacenter. Para DrissionPage con ChromiumPage, combinar un proxy residencial coherente con la geolocalización del navegador (timezone, idioma, país) produce la mejor tasa de éxito. Los proxies de datacenter funcionan para APIs públicas sin protección.
¿Cómo evitar bloqueos al implementar DrissionPage?
Usa sesiones pegadas de proxy para mantener un IP estable por tarea, implementa reintentos con backoff exponencial ante 403, respeta robots.txt y rate limits (máximo 1 petición cada 2–3 segundos por dominio), rota User-Agents coherentes con el navegador, y escala a ChromiumPage solo cuando sea necesario. Nunca reuses la misma sesión de proxy entre tareas diferentes.






