← Todos los artículos

Persistencia de Sesion en Web Scraping: Reutiliza Cookies para Raspar mas Rapido

Si tu scraper levanta un navegador headless para cada pagina, estas pagando el camino mas lento posible en cada peticion. Arrancar un navegador real cuesta desde cientos de milisegundos hasta varios segundos, consume memoria y repite una y otra vez el mismo trabajo de login y resolucion de retos.

Hay un patron mejor: calienta una sesion una sola vez en un navegador, captura las cookies y entregaselas a un cliente HTTP rapido para el grueso de tus peticiones. Esto es la persistencia de sesion, y es una de las optimizaciones de mayor impacto que puedes aplicar a un pipeline de scraping. Bien hecha, reduce tu coste por peticion en un orden de magnitud y hace que tu trafico parezca mas consistente, no menos.

Esta guia explica que es realmente una sesion, como mover una desde un navegador a un cliente HTTP normal, por que las cookies de vida corta como __cf_bm te obligan a refrescar, y como mantener todo estable en produccion.

Que es Realmente una “Sesion”

Cuando la gente dice “mantente logueado” o “manten la sesion viva”, suele referirse a las cookies. Pero una sesion es mas que un token de login. En un sitio moderno protegido por una capa anti-bot, una sesion que funciona es un paquete de cosas que deben mantenerse consistentes:

  • Cookies de autenticacion. El token que prueba que estas logueado (a menudo algo como access_token, session_id o un JWT firmado en una cookie).
  • Tokens CSRF. A veces en una cookie, a veces en una cabecera o en un campo oculto del formulario.
  • Cookies de gestion de bots. Estas son las que la gente olvida. Cloudflare establece __cf_bm (una cookie de gestion de bots de vida corta, normalmente valida durante unos 30 minutos) y, tras un reto, cf_clearance. Otros proveedores tienen sus propios equivalentes.
  • Una identidad de cliente consistente. El mismo User-Agent, el mismo conjunto amplio de cabeceras, idealmente la misma direccion IP y una huella TLS que coincida con la de un navegador real.

La trampa es tratar una sesion como “solo la cookie de login”. Copias la cookie de autenticacion en requests, funciona unos minutos y luego todo empieza a devolver 403 o a redirigir a una pagina de reto. Casi siempre es una cookie de gestion de bots que caduca, o un desajuste de huella TLS, no tu login muriendo.

El Patron Hibrido: Calienta en un Navegador, Ejecuta en un Cliente HTTP

La idea central es una division del trabajo:

  1. Usa un navegador real (o headless) para establecer la sesion. El navegador gestiona los retos de JavaScript, el flujo de login y cualquier generacion de token del lado del cliente. Esta es la parte cara, y la haces pocas veces.
  2. Exporta las cookies. Extrae todas las cookies que el navegador recogio, no solo la de login.
  3. Reproduce con un cliente HTTP rapido. Para las paginas de datos reales, usa un cliente ligero que reutilice esas cookies. Sin navegador, sin motor de JavaScript, solo HTTP.

El detalle es el fingerprinting. Una peticion requests normal tiene una firma TLS de Python que los sistemas anti-bot detectan al instante, asi que las cookies que tanto te costo generar acaban rechazadas. La solucion es usar un cliente HTTP que imite la huella TLS y HTTP/2 de un navegador. En Python, curl_cffi hace exactamente eso.

Paso 1: Calienta la Sesion en Playwright

from playwright.sync_api import sync_playwright

def warm_session(url: str) -> dict:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context()
        page = context.new_page()

        # Carga el sitio para que ejecute su JS y establezca sus cookies.
        page.goto(url, wait_until="networkidle")

        # Si hay login, hazlo aqui para que se establezcan las cookies de auth.
        # page.fill("#email", "..."); page.fill("#password", "...")
        # page.click("button[type=submit]"); page.wait_for_load_state("networkidle")

        cookies = context.cookies()
        user_agent = page.evaluate("() => navigator.userAgent")
        browser.close()

    # Aplana a un dict nombre -> valor para el cliente HTTP.
    jar = {c["name"]: c["value"] for c in cookies}
    return {"cookies": jar, "user_agent": user_agent}

Fijate en que tambien capturas el User-Agent. El cliente HTTP debe enviar el mismo, o la sesion parecera inconsistente.

Paso 2: Reproduce con curl_cffi

from curl_cffi import requests as cffi

def fetch_with_session(url: str, session: dict) -> str:
    resp = cffi.get(
        url,
        cookies=session["cookies"],
        headers={"User-Agent": session["user_agent"]},
        impersonate="chrome",  # imita la huella TLS/HTTP2 de un Chrome real
        timeout=30,
    )
    resp.raise_for_status()
    return resp.text

Ahora puedes lanzar cientos de estas llamadas por sesion calentada. Cada una es una peticion HTTP normal que lleva una huella de nivel navegador y un frasco de cookies completo. Sin sobrecarga de navegador por pagina.

Por que Tienes que Refrescar: El Problema de las Cookies de Vida Corta

Aqui es donde se caen la mayoria de las implementaciones ingenuas. Algunas cookies son duraderas (un token de login puede durar dias), pero las cookies de gestion de bots son deliberadamente de vida corta. La __cf_bm de Cloudflare es el ejemplo clasico: esta disenada para caducar en unos 30 minutos, de modo que una sesion capturada no pueda reproducirse para siempre.

Asi que una sesion no es una captura unica. Es algo vivo que tienes que rellenar. Las cookies duraderas (tu login) siguen validas; las de vida corta necesitan reacunarse. El modelo limpio es:

  • Guarda las cookies duraderas (auth) en almacenamiento a largo plazo.
  • Periodicamente reabre un navegador con esas cookies duraderas ya inyectadas, deja que el sitio te entregue cookies frescas de vida corta, y devuelve el frasco actualizado a tu cliente rapido.

Inyectar las cookies duraderas en un contexto de navegador nuevo antes de navegar significa que te saltas el login completo cada vez. Solo pagas el paso barato de “recargar y recoger tokens frescos”.

def refresh_session(url: str, durable_cookies: list[dict]) -> dict:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context()
        context.add_cookies(durable_cookies)  # inyecta las cookies de auth de larga vida
        page = context.new_page()
        page.goto(url, wait_until="networkidle")  # el sitio acuna cookies frescas de vida corta
        cookies = context.cookies()
        browser.close()
    return {c["name"]: c["value"] for c in cookies}

Ejecuta esto en un temporizador comodamente mas corto que la vida de la cookie mas corta. Si __cf_bm dura unos 30 minutos, refrescar cada 10 o 15 minutos te mantiene con seguridad dentro de la ventana.

Detectar una Sesion Caducada

No dependas solo del reloj. Los sitios cambian los TTL y una sesion puede morir antes de tiempo. Anade una comprobacion de salud barata para que tu cliente sepa cuando disparar un refresco en lugar de raspar basura en silencio.

Senales de que una sesion ha caducado:

  • Un 403 o 429 donde antes obtenias 200.
  • Una redireccion a /login, /challenge o una pantalla intermedia de Cloudflare.
  • Una respuesta 200 cuyo cuerpo es la pagina de reto, no tus datos (un bloqueo suave con HTTP 200).
  • Tu selector CSS o clave JSON esperada desaparece de repente.
def looks_blocked(resp) -> bool:
    if resp.status_code in (401, 403, 429):
        return True
    body = resp.text.lower()
    markers = ["just a moment", "verify you are human", "cf-challenge", "enable javascript"]
    return any(m in body for m in markers)

Cuando looks_blocked se dispara, vuelve a encolar la URL, dispara un refresco y reintenta. Trata una unica deteccion de caducidad como un disparador, no como un fallo.

Detalles de Produccion que Importan de Verdad

Unas pocas cosas separan una demo de un pipeline que funciona durante semanas:

  • Manten la IP consistente con la que se acunaron las cookies. Los sistemas anti-bot vinculan las sesiones de forma laxa a la red donde se crearon. Si calientas una sesion en una IP y la reproduces desde otra muy distinta, provocas un reto. Cuando uses proxies, mantén una sesion fijada a una salida estable durante toda su vida.
  • Iguala todo el perfil de cabeceras, no solo el User-Agent. El orden de las cabeceras, Accept-Language, las pistas Sec-Ch-Ua y Accept-Encoding deben parecerse al navegador con el que calentaste. El impersonate de curl_cffi gestiona la mayor parte por ti.
  • No sobrecargues una sola sesion. Una unica sesion de navegador martilleando miles de peticiones por minuto es en si misma una senal delatora. Reparte la carga entre varias sesiones calentadas y rota entre ellas.
  • Persiste las cookies en disco o en una pequena base de datos. Si tu proceso se reinicia, no querras rehacer cada login. Guarda las cookies duraderas, recargalas y refresca.
  • Rota identidades si manejas varias cuentas. Manten las cookies duraderas de cada cuenta separadas y elige una al azar por lote. Esto reparte cualquier limite de tasa por cuenta, aunque no cambia la reputacion subyacente de tu IP.

Ese ultimo punto merece honestidad. La reutilizacion de sesion resuelve la velocidad y el throttling por cuenta. No arregla una IP mala. Si tus direcciones de salida ya estan marcadas, ninguna higiene de cookies te salvara, y ahi es donde una capa de desbloqueo gestionada se gana su sitio.

Preguntas Frecuentes

Sigo necesitando un navegador si uso persistencia de sesion? Si, pero rara vez. El navegador establece y refresca la sesion; el cliente HTTP rapido hace el grueso de la descarga. Pasas de un arranque de navegador por pagina a uno cada 10 a 30 minutos.

Por que mi cookie copiada funciona en el navegador pero no en requests? Casi siempre es un desajuste de huella. requests a secas tiene una firma TLS de Python que los sistemas anti-bot detectan al instante. Usa curl_cffi con impersonate, u otro cliente que imite la huella de un navegador, y envia el mismo User-Agent.

Que es la cookie __cf_bm y por que caduca constantemente? __cf_bm es la cookie de gestion de bots de Cloudflare. Es intencionadamente de vida corta (unos 30 minutos) para que las sesiones capturadas no puedan reproducirse indefinidamente. Refresca tu sesion dentro de esa ventana.

Puedo compartir una sesion entre muchas maquinas? Puedes, pero mantenlas tras la misma IP de salida o una similar y no superes tasas de peticion sensatas. Repartir una sesion entre muchas IP a la vez es una forma habitual de invalidarla.

Para Terminar

La persistencia de sesion consiste sobre todo en respetar como funcionan realmente las sesiones: un paquete de cookies duraderas y de vida corta, ligado a una identidad de cliente y una red consistentes. Calienta una vez en un navegador, reproduce con un cliente HTTP de huella igualada, refresca antes de que caduquen las cookies de vida corta y vigila los bloqueos suaves para recalentar a tiempo.

Si prefieres no gestionar tu mismo la flota de navegadores, el refrescador de cookies y la rotacion de proxies, eso es exactamente lo que ScrapeUnblocker resuelve tras una sola llamada a la API: gestiona la sesion, la huella y el desbloqueo para que tu solo pidas una URL y recibas la pagina. Puedes leer la documentacion para desarrolladores para ver como encaja en un pipeline existente. En cualquier caso, el principio es el mismo: haz el trabajo caro una vez y reutilizalo.

Prueba ScrapeUnblocker gratis

Tasa de éxito del 95%+ · desde 0,55 € por cada 1000 llamadas · 500 solicitudes gratis al registrarte.

Pruébalo gratis → Ver precios