Cuándo tiene sentido el web scraping
El scraping es una herramienta poderosa pero hay que usarla bien. Los casos que implemento frecuentemente:
- Monitoreo de precios de competidores
- Extracción de datos de portales sin API pública
- Automatización de tareas manuales en sistemas legacy
- Agregación de información de múltiples fuentes
Siempre verifico los términos de servicio del sitio y evito saturar servidores con requests agresivos.
Setup básico con Puppeteer
npm install puppeteer
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
const page = await browser.newPage();
await page.goto('https://ejemplo.com', { waitUntil: 'networkidle0' });
const data = await page.evaluate(() => {
return Array.from(document.querySelectorAll('.producto')).map(el => ({
nombre: el.querySelector('.nombre')?.textContent?.trim(),
precio: el.querySelector('.precio')?.textContent?.trim(),
}));
});
await browser.close();
console.log(data);
Manejo de páginas dinámicas y esperas
// Esperar a que aparezca un elemento
await page.waitForSelector('.resultado', { timeout: 10000 });
// Esperar a que desaparezca un loader
await page.waitForFunction(
() => !document.querySelector('.spinner'),
{ timeout: 15000 }
);
// Scroll infinito: cargar más contenido
const autoScroll = async (page) => {
await page.evaluate(async () => {
await new Promise(resolve => {
let totalHeight = 0;
const timer = setInterval(() => {
window.scrollBy(0, 100);
totalHeight += 100;
if (totalHeight >= document.body.scrollHeight) {
clearInterval(timer);
resolve();
}
}, 100);
});
});
};
Puppeteer Extra + Stealth Plugin
Muchos sitios detectan y bloquean Puppeteer. El plugin stealth evita la mayoría de las detecciones básicas:
npm install puppeteer-extra puppeteer-extra-plugin-stealth
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({ headless: true });
Rate limiting y respeto al servidor
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
for (const url of urls) {
await page.goto(url);
// ... extraer datos
await sleep(1500 + Math.random() * 1000); // 1.5-2.5 segundos entre requests
}
Caso real: scraping de expedientes judiciales
En el proyecto Magistrar, implementé scraping del portal del Poder Judicial para actualizar automáticamente el estado de expedientes. El desafío era un sistema con CAPTCHA y sesiones. La solución: iniciar sesión con Puppeteer, mantener las cookies, y solo scrapear cuando había cambios detectados por un polling liviano previo.