batch_scrape
使用共享工作池在一次调用中抓取多个 URL。请求是同步的——直接返回完成后的结果,而不是任务句柄——并且每个 URL 都带有各自的状态,因此单个失效页面不会拖垮整批。结果同时保存 24 小时,可用 get_batch_results 重新读取。
使用场景
竞品价格扫描
在一次请求中从五十个商品页面提取同一个 CSS 字段,而不是往返五十次。
链接健康检查
提交 URL 列表,并逐条读取 http_status。无法访问的条目会以 failed 返回,并附带原因。
内容清点
把站点地图喂给批处理,收集所有标题和 canonical URL,用于审计表格。
部署后验证
检查一组关键页面是否仍返回 200,并且仍包含你期望的元素。
数据集构建
从 URL 列表中收集正文前 5,000 个字符,作为下游流水线的输入。
延后取回
现在运行批处理,稍后在另一个进程中用 get_batch_results 取回已保存的结果。
Endpoint
/api/v1/tools/batch_scrapeParameters
urls、batch_config.concurrency 和 extraction_template.fields 会改变实际行为。其余参数只做校验然后被忽略;下表逐项标明。| Name | Type | Required | Default | Description |
|---|---|---|---|---|
urls | array | Required | - | 要抓取的 URL。1 到 50 条;更长的列表会被拒绝而不是截断。 Example: [{ "url": "https://example.com/widget-a", "id": "a" }] |
batch_config | object | Optional | - | 批处理的执行设置。 Example: { "concurrency": 5 } |
extraction_template | object | Optional | - | 要从批处理中每个页面提取的字段。 Example: { "fields": [{ "name": "price", "selector": ".price" }] } |
output_config | object | Optional | - | 整体接受但完全忽略。响应始终是下方所示结构的 JSON;`format`、`include_metadata`、`include_errors` 和 `flatten_results` 均无效果。 Example: { "format": "json" } |
options | object | Optional | - | 接受但会被忽略,只有 `javascript_enabled: true` 会在 `notes` 中添加一行说明。`user_agent`、`follow_redirects`、`respect_robots_txt` 和 `rate_limit_per_domain` 不会改变托管 REST API 的抓取方式。 Example: { "javascript_enabled": false } |
respect_robots | boolean | Optional | true | 遵守每个目标站点的 robots.txt。保持 `true` 时,robots.txt 对 `CrawlForge` 禁止的 URL 会被跳过,批次的其余部分继续执行——请求仍返回 200 并给出部分结果集,而不是 403,被跳过的 URL 不计费。仅在你与目标站点另有约定时才设为 `false`——此时响应会带上一条 `warnings`,并且该覆盖会记录到你的 API key 上。 Example: true |
执行模型
在决定批量大小之前值得知道——该端点运行在 30 秒的无服务器函数中。
batch_id 是取回结果的键,而不是任务句柄。skipped 状态返回,并且不计费。单个抓取的超时为 8 秒。failed。调用本身仍然返回 200。请求示例
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" }
]
}
}'响应示例
{ "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_id在 24 小时内把它传给 [get_batch_results](/docs/api-reference/tools/get-batch-results),即可重新读取完整结果集data.total提交的条目数——始终等于 `results` 的长度data.skipped时间预算未能覆盖到的 URL。不计费data.results[].id如果你提供了 `id` 则为该值,否则为数组下标的字符串形式data.results[].status`success`、`failed` 或 `skipped`——请逐条检查它,而不是看 HTTP 状态码data.results[].text剥离 script 与 style 后的可见正文,截断到 5,000 个字符data.results[].fields模板中每个字段对应一个键。`null` 表示选择器没有匹配到任何内容data.results[].field_notes仅在某个字段无法应用时出现——例如 xpath 选择器,或解析器拒绝的 CSSdata.notes批处理级别的说明,包括你请求了但托管 API 并不支持的功能credits_used每个已尝试的 URL 收 5:这里有 3 个 URL,无跳过,因此为 15错误处理
批次无效(400 Bad Request)
VALIDATION_ERROR。urls 数组为空、条目超过 50、URL 格式错误,或 concurrency 超出 1-10 时触发。不会抓取任何内容,也不会计费。
存储不可用(503 Service Unavailable)
STORAGE_UNAVAILABLE。结果会在计费之前先持久化,因此当存储不可达时,批处理会被拒绝,而不是跑完后丢失。不计费,请重试。
批处理失败(500 Internal Server Error)
TOOL_ERROR。意外故障。单个 URL 的问题绝不会出现在这里——它们会作为 200 响应中的 failed 条目出现。
被 robots.txt 禁止(不是错误——该 URL 被跳过)
robots.txt 对 CrawlForge 禁止的 URL 会被排除在批次之外,而不会让整个批次失败:调用仍返回 200 并给出部分结果集,被跳过的 URL 不计费,因此在认定批次已完成之前,请逐个查看各 URL 的结果。若你与目标站点另有约定,可设置 respect_robots: false 予以覆盖——该覆盖会记录到你的 API key 上。该覆盖不适用于列入 CrawlForge 永久排除名单的主机——无论 respect_robots 取何值,这类主机一律被拒绝,并且同样会被跳过且不计费,该结果的 error 字段会写明主机名。data.notes 会汇总有多少 URL 被跳过以及原因。
succeeded、failed 和 skipped,或每条记录的 status。credits 费用
skipped 的 URL 不计费,在校验阶段被拒绝的批次也不计费。失败的 URL 会计费——毕竟已经尝试过抓取。包含内容:
每次调用最多 50 个 URL,并发抓取
每页返回标题与正文(5,000 个字符)
CSS 字段提取,并附逐字段说明
每个 URL 的状态与 HTTP 状态码
结果保存 24 小时,供 get_batch_results 使用
计划推荐:
Free 计划: 1,000 个一次性试用 credits = 200 个 URL
Hobby 计划: 5,000 credits = 1,000 个 URL($19/mo)
Professional 计划: 50,000 credits = 10,000 个 URL($99/mo)