CrawlForge
Guía intermedia

Guía de Procesamiento por Lotes

Escale el scraping web a miles de URL con una gestión de colas eficiente, recuperación ante errores y estrategias de optimización del rendimiento.

Uso de la herramienta batch_scrape
Gestión de colas
Recuperación ante errores
Optimización del rendimiento

1. Uso de la herramienta batch_scrape

La herramienta batch_scrape gestiona hasta 50 URL de forma concurrente con limitación de tasa integrada y notificaciones por webhook.

Scraping por lotes básico

1 credit por URL (50 URL = 50 credits)

Bash
curl -X POST https://crawlforge.dev/api/v1/tools/batch_scrape \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/page1",
      "https://example.com/page2",
      "https://example.com/page3"
    ],
    "formats": ["markdown"],
    "maxConcurrency": 5,
    "onlyMainContent": true
  }'

Procesamiento asíncrono con webhooks

Ideal para lotes grandes (100+ URL): reciba una notificación cuando finalice

Typescript
// Start batch job with webhook
const response = await fetch('https://crawlforge.dev/api/v1/tools/batch_scrape', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.CRAWLFORGE_API_KEY!,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    urls: largeUrlList, // 100+ URLs
    formats: ['markdown'],
    webhook: 'https://yourapp.com/webhook/batch-complete',
    maxConcurrency: 10
  }),
});

const { jobId } = await response.json();
console.log(`Batch job started: ${jobId}`);

// Webhook handler (Express.js example)
app.post('/webhook/batch-complete', (req, res) => {
  const { jobId, status, results, errors } = req.body;

  if (status === 'completed') {
    console.log(`Job ${jobId} completed!`);
    console.log(`Success: ${results.length} pages`);
    console.log(`Errors: ${errors.length} pages`);

    // Process results
    results.forEach(result => {
      saveToDatabase(result.url, result.content);
    });
  }

  res.sendStatus(200);
});

2. Gestión de colas

Procese miles de URL dividiéndolas en lotes y gestionando una cola.

Estrategia de división en fragmentos

Divida listas grandes de URL en lotes manejables

Typescript
// Chunk array into batches of 50
function chunkArray<T>(array: T[], size: number): T[][] {
  const chunks: T[][] = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}

// Process all URLs in batches
async function processBatches(urls: string[]) {
  const batches = chunkArray(urls, 50); // Max 50 URLs per batch
  const allResults: any[] = [];

  for (let i = 0; i < batches.length; i++) {
    const batch = batches[i];
    console.log(`Processing batch ${i + 1}/${batches.length}...`);

    const response = await fetch('https://crawlforge.dev/api/v1/tools/batch_scrape', {
      method: 'POST',
      headers: {
        'X-API-Key': process.env.CRAWLFORGE_API_KEY!,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        urls: batch,
        formats: ['markdown'],
        maxConcurrency: 10
      }),
    });

    const data = await response.json();
    allResults.push(...data.data.results);

    // Wait between batches to respect rate limits
    if (i < batches.length - 1) {
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }

  return allResults;
}

// Usage
const urls = [...]; // 500 URLs
const results = await processBatches(urls);
console.log(`Scraped ${results.length} total pages`);
Consejo profesional: Use Redis o una base de datos para almacenar su cola. Esto le permite reanudar el procesamiento si su script falla o necesita reiniciarse.

3. Recuperación ante errores

Gestione los fallos con elegancia mediante lógica de reintentos y seguimiento de errores.

Gestión robusta de errores

Typescript
interface BatchResult {
  successful: any[];
  failed: { url: string; error: string }[];
}

async function batchScrapeWithRetry(
  urls: string[],
  maxRetries = 3
): Promise<BatchResult> {
  const successful: any[] = [];
  const failed: { url: string; error: string }[] = [];
  let remainingUrls = [...urls];
  let retries = 0;

  while (remainingUrls.length > 0 && retries <= maxRetries) {
    try {
      const response = await fetch('https://crawlforge.dev/api/v1/tools/batch_scrape', {
        method: 'POST',
        headers: {
          'X-API-Key': process.env.CRAWLFORGE_API_KEY!,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          urls: remainingUrls,
          formats: ['markdown'],
          maxConcurrency: 5
        }),
      });

      const data = await response.json();

      // Separate successful and failed results
      const batchSuccessful = data.data.results.filter((r: any) => r.success);
      const batchFailed = data.data.results.filter((r: any) => !r.success);

      successful.push(...batchSuccessful);

      // Only retry failed URLs
      remainingUrls = batchFailed.map((r: any) => r.url);

      if (remainingUrls.length > 0) {
        console.log(`Retrying ${remainingUrls.length} failed URLs...`);
        retries++;
        await new Promise(resolve => setTimeout(resolve, 2000 * retries));
      }

    } catch (error) {
      console.error('Batch request failed:', error);
      retries++;

      if (retries > maxRetries) {
        // Mark all remaining URLs as failed
        failed.push(...remainingUrls.map(url => ({
          url,
          error: String(error)
        })));
        break;
      }

      await new Promise(resolve => setTimeout(resolve, 2000 * retries));
    }
  }

  return { successful, failed };
}

// Usage
const { successful, failed } = await batchScrapeWithRetry(urls);
console.log(`Success: ${successful.length}, Failed: ${failed.length}`);

// Save failed URLs for manual review
if (failed.length > 0) {
  fs.writeFileSync('failed-urls.json', JSON.stringify(failed, null, 2));
}

4. Optimización del rendimiento

Maximice el rendimiento y minimice los costos con estas estrategias de optimización.

Optimice la concurrencia
Comience con maxConcurrency: 5 y auméntelo a 10 para los planes Professional/Business
Use onlyMainContent
Establezca onlyMainContent: true para reducir el tamaño de la respuesta entre un 60 y un 80%
Elija formatos mínimos
Use formats: ["markdown"] en lugar de varios formatos (html, text, screenshot)
Almacene los resultados en caché
Guarde los datos extraídos en Redis o en una base de datos para evitar volver a hacer scraping de las mismas URL
Evite el exceso de lotes
No supere las 50 URL por lote; divídalas en varias solicitudes en su lugar
No ignore los límites de tasa
Respete los límites de tasa de su plan (Free: 5/s, Hobby: 10/s, Pro: 50/s, Business: 100/s)

Rendimiento esperado

EscenarioTiempoConfiguración
Lote pequeño (10 URL)~5 segundosmaxConcurrency: 5
Lote mediano (50 URL)~15 segundosmaxConcurrency: 10
Lote grande (500 URL)~3 minutos10 lotes × 50 URL
Lote masivo (5,000 URL)~30 minutos100 lotes × 50 URL
Próximos pasos
Continúe aprendiendo con más guías avanzadas
Optimización de credits →
Minimice los costos
Técnicas de sigilo →
Evada los sistemas anti-bots