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 obtiene hasta 50 URL de forma concurrente en una única solicitud síncrona. Cada URL vuelve con su propio estado, de modo que una página caída nunca hunde todo el lote.
Scraping por lotes básico
5 credits por URL intentada (50 URL = 250 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": [
{ "url": "https://example.com/page1" },
{ "url": "https://example.com/page2" },
{ "url": "https://example.com/page3" }
],
"batch_config": { "concurrency": 5 }
}'Sin modo asíncrono en la API REST:
batch_scrape por HTTP es síncrono: entra una solicitud, salen los resultados terminados. No hay ningún id de trabajo que consultar ni webhook: batch_id es una clave de recuperación para get_batch_results, no un identificador de trabajo. Divida en fragmentos cualquier lote de más de 50 URL como se muestra a continuación. El servidor MCP de CrawlForge sí puede ejecutar ese mismo lote de 50 URL en segundo plano con mode: 'async' y un webhook opcional.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.map(url => ({ url })),
batch_config: { concurrency: 8 },
}),
});
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.map(url => ({ url })),
batch_config: { concurrency: 5 },
}),
});
const data = await response.json();
// Each result carries its own status: 'success' | 'failed' | 'skipped'.
// 'skipped' means the request's time budget ran out before that URL was
// started — those are not charged, so they are always worth retrying.
const batchSuccessful = data.data.results.filter((r: any) => r.status === 'success');
const batchUnfinished = data.data.results.filter((r: any) => r.status !== 'success');
successful.push(...batchSuccessful);
// Only retry the URLs that did not come back successful
remainingUrls = batchUnfinished.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
batch_config.concurrency: 5. La API acepta de 1 a 10 y ejecuta como máximo 8 trabajadoresTenga en cuenta el presupuesto de tiempo
Una solicitud descarga durante unos 20 s. Las URL que nunca llega a iniciar vuelven como
skipped, y las URL omitidas no se cobranVuelva a leer, no a hacer scraping
Los resultados se guardan 24 h. Recórralos con
get_batch_results (1 credit) en lugar de repetir el lote (5 credits por URL)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: 1/s, Hobby: 2/s, Pro: 4/s, Business: 10/s)
Rendimiento esperado
| Escenario | Tiempo | Configuración |
|---|---|---|
| Lote pequeño (10 URL) | ~5 segundos | concurrency: 5 |
| Lote mediano (50 URL) | ~15 segundos | concurrency: 8 |
| Lote grande (500 URL) | ~3 minutos | 10 lotes × 50 URL |
| Lote masivo (5,000 URL) | ~30 minutos | 100 lotes × 50 URL |
Próximos pasos
Continúe aprendiendo con más guías avanzadas