Scraping de un sitio web dinámico
Los sitios web dinámicos cargan contenido mediante JavaScript después de la carga inicial de la página. Esta guía muestra cómo recolectar datos de estos sitios usando el endpoint de navegador de FourA.
El problema
Cuando envías una request HTTP estándar a un sitio web con alto uso de JavaScript, obtienes el shell HTML pero no el contenido real. Los datos que necesitas (listados de productos, precios, resultados de búsqueda) los carga JavaScript después de que la página se renderiza en un navegador.
Esto es cada vez más común con frameworks modernos como React, Vue, Angular y Next.js.
La solución: Browser Requests
El endpoint de navegador de FourA (POST /api/browser/) abre tu URL en una instancia de navegador Chrome que:
- Carga la página
- Ejecuta todo el JavaScript
- Espera a que el contenido se renderice
- Devuelve el HTML totalmente renderizado
Paso 1: Identifica lo que necesitas
Antes de hacer la request, visita la página de destino en tu navegador y usa DevTools (F12) para encontrar un fragmento de texto o elemento que confirme que el contenido se ha cargado. Por ejemplo:
- El nombre de un producto que aparece después del renderizado de JS
- Una clase CSS como
product-griden el HTML renderizado - Una cadena de texto como "results" que solo aparece cuando los datos se cargan
Paso 2: Envía una Browser Request
curl -X POST https://eu.api.foura.ai/api/browser/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products",
"timeout_ms": 15000,
"checkText": "product-grid"
}'
La opción checkText le indica a FourA que verifique que "product-grid" esté en la página una vez que haya terminado de cargar. Si no está, el request devuelve un error con checkText:product-grid not found, y un request fallido no se factura. checkText no hace que FourA espere más tiempo por el texto.
Paso 3: Parsear el HTML
La response contiene el HTML totalmente renderizado en el campo body. Analízalo con tu biblioteca preferida:
Python (BeautifulSoup)
import requests
from bs4 import BeautifulSoup
resp = requests.post("https://eu.api.foura.ai/api/browser/", headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
}, json={
"url": "https://example.com/products",
"timeout_ms": 15000,
"checkText": "product-grid"
})
html = resp.json()["body"]
soup = BeautifulSoup(html, "html.parser")
for product in soup.select(".product-card"):
name = product.select_one(".product-name").text.strip()
price = product.select_one(".product-price").text.strip()
print(f"{name}: {price}")
Node.js (cheerio)
import * as cheerio from 'cheerio';
const resp = await fetch('https://eu.api.foura.ai/api/browser/', {
method: 'POST',
headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://example.com/products',
timeout_ms: 15000,
checkText: 'product-grid'
})
});
const { body: html } = await resp.json();
const $ = cheerio.load(html);
$('.product-card').each((i, el) => {
console.log($(el).find('.product-name').text(), $(el).find('.product-price').text());
});
Solución de problemas
¿Sigues obteniendo contenido vacío?
- Verifica si la página realmente utiliza renderizado con JavaScript (compara "Ver código fuente" con DevTools)
- Aumenta
timeout_ms: algunas páginas cargan lentamente - Comprueba si la página requiere autenticación o cookies (utiliza el parámetro
cookies)
¿Aparece una página de verificación?
- Para requests individuales/HTTP, cambia al endpoint de proxy (
POST /api/proxy/) para rotación automática de IP. - Para enrutar un request de navegador a través de un proxy, pasa el parámetro
proxydel endpoint de navegador. El endpoint de proxy solo envuelve requests individuales/HTTP, no requests de navegador.
El parámetro proxy toma el proxy ID opaco que devolvió una response anterior, nunca una dirección de proxy propia. Ejecuta primero una llamada a POST /api/proxy/ (o POST /api/auto/), lee el campo proxy que devuelve y luego fíjalo:
# Step 1: let FourA find a working exit. The response carries "proxy": "A1B2C3".
curl -X POST "https://eu.api.foura.ai/api/proxy/" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"maxTries": 5, "request": {"method": "GET", "url": "https://example.com/products"}}'
# Step 2: render through that same exit.
curl -X POST "https://eu.api.foura.ai/api/browser/" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/products", "proxy": "A1B2C3", "timeout_ms": 20000}'
Enviar una dirección en lugar de un ID devuelve 400 Invalid proxy format. El patrón completo está en Reutilizar un proxy en varias requests.
Siguientes pasos
- Elegir el endpoint correcto: Cuándo usar browser vs. single
- Monitorear precios de competidores: Tutorial completo de seguimiento de precios
- Sitios protegidos: Manejar sitios protegidos
- Reutilizar un proxy en varias requests: Fijar una salida en todo un flujo de trabajo