Scarnox · Blog

Cómo scrapear sitios web renderizados con JavaScript

Muchos sitios modernos envían un documento HTML casi vacío y construyen el contenido en el navegador con JavaScript. Si tu scraper descarga la página y no encuentra productos, precios ni texto de artículos, el contenido está ahí, pero llega más tarde. Esta guía muestra cómo distinguir qué tipo de página tienes, cómo encontrar una vía más rápida que un navegador cuando existe, y cómo scrapear páginas renderizadas con Playwright en Python. Termina con una nota sobre qué hacer cuando una página renderizada muestra un captcha.

Paso 1: comprueba si el contenido está en el HTML

Abre la página con view-source: en tu navegador, o descárgala con una petición HTTP simple, y busca en el código fuente un fragmento de texto que veas en pantalla. Son habituales tres resultados:

Paso 2: llama al endpoint JSON si existe

Cuando una página obtiene sus datos de un endpoint, llamar a ese endpoint directamente suele ser la mejor opción. Es más pequeño, más rápido y más estable que la página renderizada. Copia la URL de la petición, comprueba qué cabeceras exige el sitio e intenta llamarla desde un script. Hazlo solo cuando los términos del sitio lo permitan, y respeta cualquier límite de velocidad o autenticación que el sitio espere. Un endpoint no documentado puede cambiar sin previo aviso, así que escribe tu analizador para que falle de forma ruidosa cuando cambie la forma de la respuesta.

Paso 3: renderiza la página cuando sea necesario

Si el contenido necesita de verdad el navegador, controla un navegador headless. Playwright es una buena opción para Python. El ejemplo siguiente abre un listado de productos, espera a que aparezca el contenido y lee el texto de cada tarjeta:

from playwright.sync_api import sync_playwright

URL = "https://example.com/products"  # una página que tengas permiso para scrapear

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto(URL, wait_until="domcontentloaded", timeout=60_000)
    # Espera al elemento que demuestra que los datos han llegado.
    page.wait_for_selector(".product-card", timeout=30_000)
    titles = page.locator(".product-card h2").all_inner_texts()
    browser.close()

for title in titles:
    print(title)

Esperar a un selector concreto es mucho más fiable que una pausa sleep fija. Una pausa fija es demasiado corta en un día lento o desperdicia tiempo en un día rápido. Elige el elemento que solo aparece cuando los datos ya se han cargado.

Paso 4: gestiona el scroll infinito y la paginación

Algunas páginas cargan más elementos al desplazarse. Baja hasta el final, espera a que el número de elementos crezca y para cuando deje de crecer. Las páginas con paginación numerada son más sencillas: busca el enlace a la página siguiente, síguelo y para en la última página. Establece siempre un número máximo de páginas o de desplazamientos, para que un error no mantenga tu rastreador funcionando para siempre.

def scroll_until_done(page, selector: str, max_rounds: int = 20) -> int:
    previous = -1
    for _ in range(max_rounds):
        count = page.locator(selector).count()
        if count == previous:
            break
        previous = count
        page.mouse.wheel(0, 4000)
        page.wait_for_timeout(1500)  # da tiempo a que cargue el siguiente bloque
    return previous

Paso 5: mantén el navegador económico

Renderizar es caro. Bloquea las imágenes, las fuentes y los archivos multimedia que no necesites, y reutiliza un mismo navegador para muchas páginas en lugar de lanzar uno nuevo cada vez. Cierra las páginas y los contextos cuando termines, para que la memoria no crezca durante una ejecución larga.

def block_heavy_assets(route):
    if route.request.resource_type in ("image", "font", "media"):
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_heavy_assets)

Paso 6: cuando una página renderizada muestra un captcha

A veces la página renderizada presenta un captcha antes de mostrar cualquier contenido. Si ese captcha es PopularCaptcha, el tipo de captcha activo en Scarnox, lees la sitekey de la página, solicitas un token y colocas el token en el campo del formulario que espera el sitio. La guía de PopularCaptcha en Python recorre ese paso. Otros widgets todavía no están activos, así que consulta tipos de captcha explicados antes de planificar en torno a uno.

Ten cuidado con el propio navegador. Un navegador headless que parece claramente automatizado puede activar más comprobaciones, no menos. Lee detección de navegadores headless para ver las señales a vigilar, y prefiere menos cargas de página, hechas más despacio.

Scrapea de forma responsable

Próximos pasos

Empieza con crédito de prueba gratis, sin tarjeta: crea una cuenta y prueba el flujo de PopularCaptcha en una página que sea tuya. Para ver las tarifas actuales, consulta la página de precios.