Apify Web Scraping Tutorial 2026: Deja de Escribir Scrapers que se Rompen a las 2 AM

Apify Web Scraping Tutorial 2026: Deja de Escribir Scrapers que se Rompen a las 2 AM

Programming· 7 min read

Has Pasado Dos Semanas Perfeccionando tu Scraper de Playwright. Esta Noche a las 2 AM ha Fallado.

Un cambio de CSS class. Un rate limit que no esperabas. Una sesión que se bloqueó silenciosamente.

*El problema no son tus selectores. Es que estás reinventando infraestructura que ya está resuelta. *

Llevo años construyendo scrapers para proyectos como gestoriascercademi.com o findemergencyplumber.com. Y lo que he aprendido es que el 90% del tiempo de debugging no va de extraer datos — va de gestionar sesiones rotas, proxies caídos, colas de peticiones que se corrompen.

Apify lleva años resolviendo eso. Pero la mayoría lo trata como "esa plataforma de scrapers pre-construidos". No entienden lo que realmente tienen: un runtime serverless con un SDK open-source (Crawlee) que hace que tus scrapers sean 2-3x más fiables sin que tengas que escribir la plomería.

Este es el tutorial que me hubiera gustado tener hace dos años.

El Error que el 90% de los Desarrolladores Comete al Construir Scrapers

Crees que el scraping es fácil. Tomas Playwright, escribes un page.goto(), seleccionas elementos con page.locator(), y vuelcas a un CSV.

Funciona en local. Lo despliegas en un cron job de GitHub Actions. Y a las 48 horas el scraper está muerto.

El enfoque naive (lo que hace el 90%):

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Este scraper funciona exactamente hasta que el sitio cambia una clase CSS, te rate-limean, o tu IP se bloquea. *No hay gestión de nada. *

El problema es que piensas que escribir scrapers va de selectores. No va de selectores. Va de state management.

Un scraper de producción necesita:

  • Session Pool: saber qué sesiones están bloqueadas y rotarlas automáticamente
  • Retry Logic: reintentar con una sesión, proxy y fingerprint diferente
  • Request Queue: deduplicar URLs, priorizar rutas, persistir estado si crashea
  • Proxy Rotation: cambiar de IP cuando te baneen
  • Error Recovery: no morir en el primer 403

Todo eso es plomería. Y Apify + Crawlee te lo dan gratis.

Lo que Crawlee SDK Hace por Ti (y No Sabías)

Crawlee es el SDK open-source de Apify. Licencia MIT. Funciona en local, en cualquier cloud, en CI/CD. No necesitas la plataforma de Apify para usar Crawlee.

Pero cuando juntas Crawlee con Apify Actors, obtienes algo que la mayoría de desarrolladores no construye hasta que ya es demasiado tarde.

El enfoque correcto con Crawlee:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Fíjate en lo que acabas de escribir sin escribir:

  1. Session Pool — cada 10 peticiones, Crawlee rota la sesión automáticamente
  2. Retry automático — si una petición da 403 o 429, reintenta con nueva sesión + proxy
  3. Request QueueenqueueLinks() descubre enlaces, los deduplica y los encola
  4. Proxy rotation — si configuras proxies, Crawlee los rota transparentemente

*Eso son semanas de trabajo que te ahorras. *

### El Gran Malentendido: Cheerio vs Playwright

La mayoría elige Playwright porque "es más potente". Y tienen razón — para SPAs, es necesario.

Pero PlaywrightCrawler ejecuta un navegador completo. Eso significa:

  • 10-50x más lento que CheerioCrawler
  • Mucho más consumo de RAM y CPU
  • Más caro en cloud (cada instancia de navegador pesa)

El patrón correcto es:

Usa CheerioCrawler como default (solo parsea HTML, sin navegador)

Usa PlaywrightCrawler solo cuando el sitio renderiza JS (React, Vue, Angular)

Usa PlaywrightCrawler para descubrir API endpoints de SPAs, luego cambia a CheerioCrawler contra esas APIs

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Para sitios estáticos, esto vuela. *Sin navegador. Sin overhead. Sin sorpresas. *

### La Capa Invisible: Request Queue y Session Pool

Aquí es donde el 95% de los scrapers caseros se rompe.

Request Queue

Cuando scrapeas un sitio con paginación o enlaces internos, necesitas:

  • Deduplicación: la misma URL no se crawlea dos veces
  • Priorización: ciertas rutas primero, otras después
  • Persistencia: si el scraper crashea, la cola se guarda y puede reanudarse

Crawlee te da todo eso con enqueueLinks() y RequestQueue automático.

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

*Si construyes esto manualmente, te lleva días. Crawlee lo hace en una línea. *

Session Pool

Este es el héroe silencioso de los scrapers de producción.

Crawlee mantiene un pool de sesiones. Cada sesión tiene un ID único, un proxy asociado, y un contador de uso. Cuando una sesión devuelve 403 o 429, Crawlee:

  1. Marca esa sesión como bloqueada
  2. La elimina del pool
  3. Reintenta la petición con una sesión nueva
  4. Usa un proxy diferente (si configuraste proxy rotation)
[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

*Esto es lo que separa un scraper de hobby de un scraper de producción. *

### El Framework: El Patrón de 5 Capas para Scrapers de Producción

No te lances a escribir scraping sin estructura. Usa este patrón que he validado en proyectos reales:

Capa 1 — Elección de Crawler

  • ¿El sitio es estático? → CheerioCrawler
  • ¿El sitio renderiza JS? → PlaywrightCrawler
  • ¿Necesitas velocidad máxima en contenido estático dentro de una SPA? → PlaywrightCrawler para descubrir API endpoints, luego CheerioCrawler contra las APIs

Capa 2 — Anti-Bloqueo

  • Configura useSessionPool: true
  • Define maxUsageCount (renueva sesión cada N peticiones)
  • Configura maxRequestRetries: 3 como mínimo
  • Añade proxies (datacenter para volumen, residential para sitios agresivos)

Capa 3 — Request Queue

  • Usa enqueueLinks() para descubrimiento automático
  • Define maxRequestsPerCrawl para no morir en sitios infinitos
  • Usa etiquetas (label) para diferenciar tipos de página
  • La cola persiste automáticamente si el scraper crashea

Capa 4 — Extracción

  • Define requestHandler limpio: extrae datos y llama a pushData()
  • No pongas lógica de negocio aquí — solo extracción
  • Valida datos antes de guardarlos

Capa 5 — Despliegue como Apify Actor

  • Dockeriza el scraper
  • Define input/output JSON schema
  • Despliega en Apify cloud para scheduling automático
  • Configura webhooks para notificaciones

### Cómo Desplegar tu Scraper como Apify Actor

Este es el paso que transforma un script en un servicio.

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Acompaña con un actor.json:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Despliega con:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

*Ahora tu scraper se ejecuta solo. Cada lunes a las 9 AM. Sin que toques nada. *

La Objeción que Vas a Poner (y por Qué No te la Compres)

"No quiero lock-in con Apify."

Crawlee es MIT. Corre en tu máquina, en GitHub Actions, en Railway, en tu VPS. No necesitas Apify cloud para nada. Las ventajas del SDK (Session Pool, Request Queue, retry automático) funcionan sin la plataforma.

"Apify es overkill para scrapers simples."

Vale si tu scraper es un script de una página que ejecutas una vez. Pero el threshold donde Crawlee paga la inversión es sorprendentemente bajo: dos páginas con paginación o un solo sitio con rate limiting. *El tiempo que pierdes debuggeando un scraper bloqueado supera el tiempo de setup. *

"Los navegadores headless son demasiado lentos y caros."

Usa CheerioCrawler como default. PlaywrightCrawler solo cuando toque. Crawlee te deja mezclar ambos en un mismo proyecto.

Lo que te Llevas

La mayoría de los desarrolladores pierde semanas escribiendo plomería que Crawlee ya resuelve. Session management, retry logic, request queues, proxy rotation — todo eso es infraestructura que no deberías construir tú.

El patrón de 5 capas te da una plantilla que funciona. Elige el crawler correcto. Configura anti-bloqueo. Usa la request queue. Extrae limpio. Despliega como Actor.

*El scraping no va de selectores. Va de state management. Y Apify + Crawlee son la mejor forma de no tener que pensarlo. *

La próxima vez que tu scraper falle a las 2 AM, que no sea porque te faltaba un session pool.

Artículos relacionados

---

¿Quieres recibir contenido como este cada semana? Suscríbete a mi newsletter

Brian Mena

Brian Mena

Software engineer building profitable digital products: SaaS, directories and AI agents. All from scratch, all in production.

LinkedIn