scrape
一次抓取即可完成的统一多格式提取。对同一次页面加载请求 markdown、HTML、原始 HTML、纯文本、链接、元数据、截图或 JSON——所有请求的格式都由同一次抓取提供,某个格式失败时会以警告形式返回,而不会让整次调用失败。加上带查询的 highlights 或 question 格式,只返回匹配的句子、表格行和代码块——页面逐字原文并附带指向 markdown 的偏移量,全程没有模型参与——只多 1 credit。传入 escalate: true 后,若返回的是反爬墙而不是页面,同一次调用会通过 stealth 浏览器重新抓取一次,加收 5 credits。
使用场景
一次调用替代四次
在一次请求中拿到页面的 markdown、链接和元数据,无需串联 fetch_url、extract_links 和 extract_metadata。
可直接喂给 LLM 的 markdown
开启 onlyMainContent 并请求 markdown,把干净、无模板噪声的页面文本直接送入 RAG 流水线或提示词。
存档快照
同时请求 rawHtml 与 markdown,只需一次抓取即可同时保留精确的源代码和一份干净的可读副本。
一次抓取,多种格式
六种格式与一种格式同样只需 2 credits,因此需要 markdown、links 与 metadata 的流水线应当在一次调用中一并请求,而不是分三次。
引用页面,而不是概括它
用查询请求 highlights,或用问题请求 question,只拿到匹配的句子、表格行和代码块——页面逐字原文,并附带指向同一次调用 markdown 的偏移量,让智能体引用原文而不是转述。与做摘要的抓取工具不同,全程没有模型参与。
Endpoint
/api/v1/tools/scrapeParameters
highlights 或 question 格式加收 1 credit,每次请求只收一次,不论包含一种还是两种。使用 escalate: true 时,预估值即上限:7 credits(与按查询范围限定的格式同用时为 8);升级阶段的 5 credits 仅在普通抓取被拦下且该阶段真正执行时才收取。| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Required | - | 要抓取的 URL(必须包含协议:http:// 或 https://) Example: https://example.com |
formats | array | Optional | ["markdown"] | 要返回的输出格式。可选一个或多个:`markdown`、`html`、`rawHtml`、`text`、`links`、`metadata`,另加两种按查询范围限定的对象格式:`{ "type": "highlights", "query": "…", "max_highlights": 10, "mode": "extractive" }` 返回与 `query` 最匹配的句子和代码块(`max_highlights` 取 1–50,默认 10)——在托管 REST API 上 `kind` 为 `sentence` 或 `code_block`;`table_row` 单元由 MCP 服务器返回,其 markdown 会把表格保留为竖线分隔的行,而 REST API 会把表格压平为文本;`{ "type": "question", "question": "…", "mode": "extractive" }` 返回由最匹配段落拼成的 `answer`。两者都返回页面逐字原文;每个单元带有指向同一次调用 `markdown` 格式的 `offset` 和 `length`(`onlyMainContent` 设置相同),因此若要带定位符引用,请同时请求 `markdown`。`mode: "model"` 在此会以 400 被拒绝——它需要 LLM,仅在 MCP 服务器上可用。`screenshot` 与 `json-schema` 能通过校验,但随后会以 400 被拒绝——它们需要浏览器或 LLM,而托管 REST API 并不提供。 Example: ["markdown", { "type": "highlights", "query": "Starter plan price" }, { "type": "question", "question": "How much does the Starter plan cost?" }] |
onlyMainContent | boolean | Optional | true | 剥离导航、页眉和页脚,只返回正文主体内容。 Example: true |
escalate | boolean | Optional | false | 选择加入:当普通抓取返回的是反爬墙而不是页面时,自动通过 stealth 浏览器重试一次——Cloudflare、Amazon、DataDome、PerimeterX、Akamai 或 Vercel 的挑战页、空壳页面,或标题为错误提示的短占位页。普通抓取始终先执行;只有在被拦下时,同一次调用才会用 stealth 浏览器渲染该页面,并从渲染结果中派生出所有请求的格式,因此被拦的页面只需一次调用而不是两次。升级复用与 [stealth_mode](/docs/api-reference/tools/stealth-mode) 相同的 stealth 路径和同一道 robots.txt 校验,不会新增任何针对反爬防护的处理手段。若 stealth 渲染同样被拒,结果仍作为被拦截的页面返回,带 `escalated: true` 且不计费:升级省下的是第二次往返,并不保证拿到页面。当普通抓取失败只是因为页面需要 JavaScript 才能渲染时,它最为可靠。响应随后会带上 `escalated`,当其为 `true` 时还会带上 `stealth`。仅在升级阶段真正执行时加收 5 credits。仅在 MCP 服务器上,被某主机拦下的记录会保留 24 小时,因此下一次对该主机的 `escalate: true` 调用会跳过注定失败的普通抓取,并在警告中说明。 Example: true |
escalate_engine | string | Optional | playwright | 升级阶段使用的浏览器引擎:"playwright"(默认)或 "camoufox"(基于 Firefox,抗检测能力更强;仅在后端已安装时可用)。除非 `escalate` 为 `true` 且普通抓取被拦下,否则忽略此参数。 Example: camoufox |
respect_robots | boolean | Optional | true | 遵守目标站点的 robots.txt。保持 `true` 时,robots.txt 对 `CrawlForge` 禁止的路径会在抓取之前以 403 拒绝,且不扣除 credits。仅在你与目标站点另有约定时才设为 `false`——此时响应会带上一条 `warnings`,并且该覆盖会记录到你的 API key 上。 Example: true |
max_inline_chars | number | Optional | 40000 | 内联返回的最大结果大小,以其 JSON 的字符数计(1,000-10,000,000)。超过后,响应会携带 `preview`(markdown的前 `max_inline_chars` 个字符)、`result_handle`、`total_chars`、`truncated: true` 和 `expires_at`,其余部分由 [read_result](/docs/api-reference/tools/read-result) 读取,每次调用 1 credit。已存储的结果保留 1 小时。 Example: 40000 |
redact_pii | boolean | object | Optional | false | 在结果被存储或返回之前,从本次调用返回的文本中移除个人数据。 `true` 是 `{ mode: "fast" }` 的简写:四个正则类别全开,以标签替换。只要请求了脱敏,响应就会在 `data` 内带上 `redaction: { entities, count, mode }`,即使没有任何匹配(`count: 0`)也会带上,因此“什么都没找到”永远不会被误认为“参数被忽略了”;没有命中的类别会被省略,而不是报成 `0`。脱敏在结果存储**之前**执行,因此超出阈值、之后再用 [read_result](/docs/api-reference/tools/read-result) 读回的结果本身就已脱敏。两条刻意的边界:地址类字段(`url`、`link`、`href`、`canonical_url`)从不脱敏;由文本派生的计数(`content_length`、`word_count`、`character_count`)描述的是抽取时的文本,即脱敏之前的文本。 Example: true |
请求示例
cURL
curl -X POST https://crawlforge.dev/api/v1/tools/scrape \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"formats": [
"markdown", "links", "metadata",
{ "type": "highlights", "query": "professional plan price per month" }
],
"onlyMainContent": true,
"escalate": true
}'TypeScript
// npm install crawlforge-sdk
import { CrawlForge, ToolError } from 'crawlforge-sdk';
const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });
try {
const result = await client.scrape({
url: 'https://example.com',
formats: [
'markdown', 'links', 'metadata',
// 1 extra credit: the matching sentences, table rows and code blocks, verbatim, with offsets
{ type: 'highlights', query: 'professional plan price per month' },
],
onlyMainContent: true,
// Only when the plain fetch meets a bot wall: one stealth render in this same call (5 extra credits)
escalate: true,
});
// result.data is untyped in crawlforge-sdk 0.1 — its shape is the Response Example below.
const { formats } = result.data as {
formats: { markdown: string; links: string[]; metadata: { title: string }; highlights: { text: string }[] };
};
console.log('Markdown:', formats.markdown);
console.log('Links found:', formats.links.length);
console.log('Title:', formats.metadata.title);
// Each highlight is verbatim page text; offset/length index formats.markdown.
console.log('Best match:', formats.highlights[0]?.text);
// A success with warnings is a PARTIAL result — some formats came back, others didn't.
if (result.warnings.length > 0) {
console.warn('Partial result:', result.warnings);
}
console.log('Credits used:', result.creditsUsed);
console.log('Credits remaining:', result.creditsRemaining);
} catch (err) {
// A bot wall the stealth render could not pass either: not charged, blocked.vendor names it.
if (err instanceof ToolError && err.blocked) {
console.error('Blocked by', err.blocked.vendor, '— escalated:', err.escalated);
} else {
throw err;
}
}Python
# pip install crawlforge
from crawlforge import CrawlForge, ToolError
client = CrawlForge() # reads CRAWLFORGE_API_KEY
try:
result = client.scrape(
url='https://example.com',
formats=[
'markdown', 'links', 'metadata',
# 1 extra credit: the matching sentences, table rows and code blocks, verbatim, with offsets
{'type': 'highlights', 'query': 'professional plan price per month'},
],
onlyMainContent=True,
# Only when the plain fetch meets a bot wall: one stealth render in this same call (5 extra credits)
escalate=True,
)
except ToolError as e:
# A bot wall the stealth render could not pass either: not charged, blocked names the vendor.
print(f"Blocked: {e.blocked} (escalated: {e.escalated})")
raise
# result.data is a plain dict — its shape is the Response Example below.
formats = result.data['formats']
print(f"Markdown: {formats['markdown']}")
print(f"Links found: {len(formats['links'])}")
print(f"Title: {formats['metadata']['title']}")
# Each highlight is verbatim page text; offset/length index formats['markdown'].
print(f"Best match: {formats['highlights'][0]['text']}")
# A success with warnings is a PARTIAL result — some formats came back, others didn't.
if result.warnings:
print(f"Partial result: {result.warnings}")
print(f"Credits used: {result.credits_used}")
print(f"Credits remaining: {result.credits_remaining}")响应示例
{ "success": true, "data": { "url": "https://example.com", "formats": { "markdown": "# Example\n\nMain content scraped from https://example.com. The Starter plan costs $12 per month and includes three seats. Annual billing lowers the Starter plan to $10 per month.", "highlights": [ { "text": "The Starter plan costs $12 per month and includes three seats.", "kind": "sentence", "offset": 58, "length": 62, "score": 6.612 }, { "text": "Annual billing lowers the Starter plan to $10 per month.", "kind": "sentence", "offset": 121, "length": 56, "score": 5.809 } ], "answer": { "text": "The Starter plan costs $12 per month and includes three seats.", "grounded": true, "evidence": [ { "text": "The Starter plan costs $12 per month and includes three seats.", "kind": "sentence", "offset": 58, "length": 62, "score": 6.612 } ] } }, "escalated": true, "stealth": { "engine": "playwright", "vendor_detected": "cloudflare" }, "scraped_at": "2026-08-26T14:30:00.000Z" }, "credits_used": 8, "credits_remaining": 992, "processing_time": 4218}data.url实际抓取的 URL。data.formats每个所请求的格式对应一个键——提取到的内容位于此对象内,而不在 data 的顶层。data.formats.markdown转换为 markdown 的正文内容(请求 `markdown` 时出现)。data.formats.highlights与 `query` 匹配、排名最高的句子和代码块,逐字原文(请求 `highlights` 格式时出现)。每个单元带有 `text`、`kind`(托管 REST API 上为 `sentence` 或 `code_block`;`table_row` 单元由 MCP 服务器返回,其 markdown 会把表格保留为竖线分隔的行,而 REST API 会把表格压平为文本)、`offset`、`length` 和 `score`——后者是未归一化的 BM25 相关度值,只用于排序,不是 0–1 的置信度。data.formats.highlights.offset指向同一次调用 `markdown` 格式的字符索引(`onlyMainContent` 设置相同):`markdown.slice(offset, offset + length) === text`。data.formats.answer对 `question` 的回答(请求 `question` 格式时出现):`text` 是最匹配证据的拼接,`evidence` 列出最多 5 个支撑单元。data.formats.answer.grounded在 REST API 上恒为 `true`——文本是页面逐字原文,不做任何合成。data.escalated升级阶段是否执行过(仅当请求传入 `escalate: true` 时出现)。`false` 表示普通抓取拿到了页面,只按基础价计费。data.stealth页面是如何渲染的(仅当 `escalated` 为 `true` 时出现):`engine` 是实际运行的浏览器,`vendor_detected` 指出普通抓取撞上的反爬防护厂商——`cloudflare`、`amazon`、`datadome`、`perimeterx`、`akamai` 或 `vercel`——当拦截表现为空壳页面或错误占位页而非具名挑战页时为 `null`。data.scraped_at本次抓取的 ISO 8601 时间戳。credits_used本次请求扣除的 credits——每次 scrape 固定 2 个,与请求了多少种格式无关;包含 `highlights` 或 `question` 格式时再加 1 个;升级阶段执行时再加 5 个。此处为 2 + 1 + 5。credits_remaining您剩余的 credits 余额。错误处理
输入无效(400 Bad Request)
URL 格式无效,formats 中包含受支持列表之外的值,或某个 highlights / question 格式请求了 mode: "model"——它需要 LLM,仅在 MCP 服务器上可用。传入该字段时至少需要一种格式。
URL 被拦截(403 Forbidden)
目标解析到私有、内网或链路本地地址,被 SSRF 防护拒绝。只能抓取公网可访问的 URL。
credits 不足(402 Payment Required)
你的账户 credits 不足。购买更多 credits 或升级你的计划。
超出速率限制(429 Too Many Requests)
你已超出所在计划的速率限制。稍等片刻,或升级你的计划以获得更高上限。
升级后端未配置(503 TOOL_NOT_AVAILABLE)
escalate: true 的 stealth 阶段运行在 CrawlForge 执行后端上。该后端未配置时,升级阶段返回 503,且不为此扣除任何 credits。
被 robots.txt 拦截(403 Forbidden)
目标站点的 robots.txt 对 CrawlForge 禁止了该路径。若你与目标站点另有约定,可设置 respect_robots: false 予以覆盖——该覆盖会记录到你的 API key 上。该覆盖不适用于列入 CrawlForge 永久排除名单的主机——无论 respect_robots 取何值,这类主机一律被拒绝。
markdown、links 与 metadata 与只请求一种格式一样,都是 2 credits——所有格式都源自同一次页面加载。请在一次调用中把可能需要的都要齐;highlights 或 question 格式只加收 1 credit,按次而非按格式计。credits 成本
highlights 或 question 格式加收 1 credit,每次请求只收一次,不论包含一种还是两种。使用 escalate: true 的调用预估最多 7 credits(与按查询范围限定的格式同用时为 8),仅当普通抓取返回反爬墙且 stealth 阶段执行时才收取 5 credits 的升级附加费——绝不会超过预估值。Free 计划: 1,000 个一次性 credits = 500 次请求
Hobby 计划: 每月 5,000 credits = 2,500 次请求(19 美元/月)
Professional 计划: 每月 50,000 credits = 25,000 次请求(99 美元/月)
Business 计划: 每月 250,000 credits = 125,000 次请求(399 美元/月)