batch_scrape
Descargue muchas URL en una sola llamada con un grupo compartido de trabajadores. La solicitud es síncrona (devuelve los resultados terminados, no un identificador de trabajo) y cada URL vuelve con su propio estado, así que una página caída nunca hunde el lote. Los resultados también se almacenan durante 24 horas y se pueden releer con get_batch_results.
Casos de uso
Barridos de precios de la competencia
Extraiga el mismo campo CSS de cincuenta páginas de producto en una sola solicitud, en lugar de cincuenta viajes de ida y vuelta.
Comprobaciones de salud de enlaces
Envíe una lista de URL y lea http_status en cada entrada. Todo lo inalcanzable vuelve como failed con el motivo adjunto.
Inventarios de contenido
Alimente el lote con un sitemap y recopile todos los títulos y URL canónicas para una hoja de cálculo de auditoría.
Verificación tras el despliegue
Compruebe que un conjunto de páginas críticas sigue devolviendo 200 y sigue conteniendo el elemento que espera.
Construcción de conjuntos de datos
Recopile los primeros 5.000 caracteres del texto del body de una lista de URL como entrada para un pipeline posterior.
Recogida diferida
Ejecute el lote ahora y recupere después los resultados almacenados desde otro proceso con get_batch_results.
Endpoint
/api/v1/tools/batch_scrapeParameters
urls, batch_config.concurrency y extraction_template.fields cambian su comportamiento. Todo lo demás se valida y luego se ignora; cada caso se indica en la tabla siguiente.| Name | Type | Required | Default | Description |
|---|---|---|---|---|
urls | array | Required | - | Las URL que se descargarán. Entre 1 y 50 entradas; una lista más larga se rechaza en lugar de truncarse. Example: [{ "url": "https://example.com/widget-a", "id": "a" }] |
batch_config | object | Optional | - | Ajustes de ejecución del lote. Example: { "concurrency": 5 } |
extraction_template | object | Optional | - | Campos que se extraerán de cada página del lote. Example: { "fields": [{ "name": "price", "selector": ".price" }] } |
output_config | object | Optional | - | Se acepta y se ignora por completo. Las respuestas siempre son JSON con la forma que se muestra abajo; `format`, `include_metadata`, `include_errors` y `flatten_results` no tienen efecto. Example: { "format": "json" } |
options | object | Optional | - | Se acepta y se ignora, salvo que `javascript_enabled: true` añade una línea explicativa a `notes`. `user_agent`, `follow_redirects`, `respect_robots_txt` y `rate_limit_per_domain` no cambian la descarga en la API REST alojada. Example: { "javascript_enabled": false } |
respect_robots | boolean | Optional | true | Respeta el robots.txt de cada sitio de destino. Con el valor `true`, una URL que robots.txt no permita a `CrawlForge` se omite y el resto del lote continúa: la solicitud sigue devolviendo 200 con un conjunto de resultados parcial en lugar de un 403, y una URL omitida no se cobra. Póngalo en `false` solo para destinos con los que tenga su propio acuerdo: la respuesta incluye entonces una entrada `warnings` y la anulación queda registrada en su API key. Example: true |
Modelo de ejecución
Conviene saberlo antes de dimensionar un lote: este endpoint se ejecuta dentro de una función serverless de 30 segundos.
batch_id es una clave de recuperación, no un identificador de trabajo.skipped y no se cobran. Cada descarga individual expira a los 8 s.failed. La llamada en sí sigue devolviendo 200.Ejemplos de solicitud
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/widget-a", "id": "a" },
{ "url": "https://example.com/widget-b", "id": "b" }
],
"batch_config": { "concurrency": 5 },
"extraction_template": {
"fields": [
{ "name": "price", "selector": ".price" },
{ "name": "canonical", "selector": "link[rel=canonical]", "attribute": "href" }
]
}
}'Ejemplo de respuesta
{ "success": true, "data": { "batch_id": "fd599a27-9ca9-4022-9a57-b02af57c387b", "total": 3, "succeeded": 2, "failed": 1, "skipped": 0, "results": [ { "id": "a", "url": "https://example.com/widget-a", "status": "success", "http_status": 200, "title": "Widget A — Acme", "text": "Widget A$24.00In stock and ready to ship.", "fields": { "price": "$24.00", "canonical": "https://example.com/widget-a", "sku": null }, "field_notes": [ "sku: xpath selectors are not supported on the hosted REST API — use a CSS selector" ] }, { "id": "b", "url": "https://example.com/widget-b", "status": "success", "http_status": 200, "title": "Widget B — Acme", "text": "Widget B$31.50Backordered until March.", "fields": { "price": "$31.50", "canonical": "https://example.com/widget-b", "sku": null } }, { "id": "c", "url": "https://example.com/gone", "status": "failed", "http_status": 404, "error": "HTTP 404" } ], "notes": [ "Results are stored for 24h and retrievable with get_batch_results (batch_id: fd599a27-9ca9-4022-9a57-b02af57c387b)." ], "completed_at": "2026-08-27T02:09:44.001Z" }, "credits_used": 15, "credits_remaining": 990, "processing_time": 3140}data.batch_idPáselo a [get_batch_results](/docs/api-reference/tools/get-batch-results) dentro de las 24 horas para releer el conjunto completodata.totalEntradas enviadas: siempre igual a la longitud de `results`data.skippedURL que el presupuesto de tiempo nunca alcanzó. No se cobrandata.results[].idSu `id` si lo proporcionó; en caso contrario, el índice del array como cadenadata.results[].status`success`, `failed` o `skipped`: compruebe esto en cada entrada, no el estado HTTPdata.results[].textTexto visible del body con los scripts y estilos eliminados, cortado a 5.000 caracteresdata.results[].fieldsUna clave por cada campo de la plantilla. `null` significa que el selector no coincidió con nadadata.results[].field_notesSolo aparece cuando un campo no se pudo aplicar: un selector xpath, o CSS que el analizador rechazódata.notesObservaciones a nivel de lote, incluido todo lo que haya pedido y que la API alojada no hacecredits_used5 por cada URL intentada: aquí 3 URL, ninguna omitida, así que 15Manejo de errores
Lote no válido (400 Bad Request)
VALIDATION_ERROR. Se produce con un array urls vacío, más de 50 entradas, una URL mal formada o un concurrency fuera de 1-10. No se descarga nada y no se cobra nada.
Almacenamiento no disponible (503 Service Unavailable)
STORAGE_UNAVAILABLE. Los resultados se guardan antes de facturar, así que si no se puede acceder a ese almacén el lote se rechaza en lugar de ejecutarse y perderse. No se cobra nada. Reintente.
El lote falló (500 Internal Server Error)
TOOL_ERROR. Un fallo inesperado. Los problemas de una URL concreta nunca aparecen aquí: se muestran como entradas failed dentro de una respuesta 200.
No permitido por robots.txt (sin error: la URL se omite)
Una URL que robots.txt no permite a CrawlForge se deja fuera del lote en lugar de hacerlo fallar: la llamada sigue devolviendo 200 con un conjunto de resultados parcial y la URL omitida no se cobra, así que revise los resultados por URL antes de dar el lote por completo. Establezca respect_robots: false para anularlo en destinos con los que tenga su propio acuerdo: la anulación queda registrada en su API key. La anulación no alcanza a un host incluido en la lista de exclusión permanente de CrawlForge: ese se rechaza sea cual sea el valor de respect_robots, y se omite y no se cobra igual que los demás, con el host indicado en el campo error de ese resultado. data.notes resume cuántas URLs se omitieron y por qué.
succeeded, failed y skipped —o el status de cada entrada— antes de dar el lote por completo.Costo en credits
skipped porque se agotó el presupuesto de tiempo no se cobran, y un lote rechazado en la validación no cuesta nada. Las URL fallidas sí se cobran: la descarga se intentó.Qué incluye:
Hasta 50 URL por llamada, descargadas de forma concurrente
Título y texto del body por página (5.000 caracteres)
Extracción de campos CSS con notas por campo
Estado y código HTTP por URL
Almacenamiento de resultados durante 24 horas para get_batch_results
Recomendaciones por plan:
Plan Free: 1,000 credits de prueba por única vez = 200 URL
Plan Hobby: 5,000 credits = 1,000 URL ($19/mo)
Plan Professional: 50,000 credits = 10,000 URL ($99/mo)