使用场景
从 JavaScript 渲染的页面取得精确价格
价格、库存和 ID 来自站点自身的状态,而不是由模型阅读渲染后的文本得出,因此无从编造。
普通抓取看不到的列表
客户端渲染的搜索结果和商品网格,通常在首次响应的 __NEXT_DATA__ 或 RSC 负载中就已经存在。
比 LLM 提取更省
2 credits,而 extract_with_llm 或 extract_structured 为 3 credits,而且不必等待推理步骤。
审查站点对自身发布了什么
found 会报告页面上的每一个状态来源及其大小,往往比可见界面所展示的更多。
Endpoint
/api/v1/tools/extract_embedded_stateParameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Required | - | 要读取嵌入状态的页面。 Example: https://example.com/products/widget |
path | string | Optional | - | 只返回一个子树,而不是整个负载。仅支持点号分隔的键和数组索引——这不是 JSONPath,因此没有通配符、过滤器、切片或递归下降。无法解析的路径会返回 400,并列出中断处可用的键,且不消耗 credits。 Example: next_data.props.pageProps |
user_agent | string | Optional | - | 覆盖发送给目标站点的 User-Agent。请求仍以 CrawlForge 的身份签名;签名覆盖的是 authority,而不是该请求头。 Example: MyCompanyBot/1.0 |
respect_robots | boolean | Optional | true | 遵守目标站点的 robots.txt。保持为 `true` 时,对 `CrawlForge` 禁止的路径会在抓取之前以 403 拒绝,并且不扣除 credits。只有在您与目标站点另有协议时才设为 `false`——此时响应会带有 `warnings` 条目,并且该覆盖会记录在您的 API key 上。 Example: true |
timeout | number | Optional | 20000 | 抓取超时(毫秒),取值 1000 到 60000。状态负载常常有数兆字节,因此默认值高于更轻量的提取工具。 Example: 20000 |
max_inline_chars | number | Optional | 40000 | 内联大小阈值,以结果 JSON 的字符数计(1,000-10,000,000)。`extract_embedded_state` 从不截断——完整状态始终内联返回——但超过此大小时,响应还会携带 `result_handle`、`total_chars` 和 `truncated: false`,因此 [read_result](/docs/api-reference/tools/read-result) 可以搜索已存储的副本或从中读取单个 `json_path`,每次调用 1 credit。已存储的结果保留 1 小时。 Example: 40000 |
请求示例
cURL - 读取完整状态
curl -X POST https://crawlforge.dev/api/v1/tools/extract_embedded_state \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products/widget"
}'TypeScript - 用 path 缩小范围
// npm install crawlforge-sdk
import { CrawlForge, ValidationError } from 'crawlforge-sdk';
const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });
try {
const result = await client.extractEmbeddedState({
url: 'https://example.com/products/widget',
// Dotted keys and array indexes. Not JSONPath: no wildcards or filters.
path: 'next_data.props.pageProps',
});
// result.data is untyped in crawlforge-sdk 0.1 — its shape is the Response Example below.
const { found, data } = result.data as {
found: { name: string; variable: string; bytes: number }[];
data: { product: { price: number } };
};
// Every state source on the page, largest first, whether or not it was scoped.
for (const source of found) {
console.log(source.name, source.variable, source.bytes);
}
// The values are the site's own, so they can be used as they are.
console.log(data.product.price);
} catch (err) {
// A path that does not resolve is a 400 naming the keys that were available.
if (err instanceof ValidationError) {
console.error(err.message);
} else {
throw err;
}
}Python - 先发现,再缩小范围
# pip install crawlforge
from crawlforge import CrawlForge
client = CrawlForge() # reads CRAWLFORGE_API_KEY
# 1. Discover what the page carries. Nothing is truncated, so this can be big.
discovery = client.extract_embedded_state(
url='https://example.com/products/widget',
)
# discovery.data is a plain dict — its shape is the Response Example below.
for source in discovery.data['found']:
print(source['name'], source['variable'], source['bytes'])
# This tool's warnings live inside data, next to the state itself.
for warning in discovery.data['warnings']:
print('warning:', warning)
# 2. Ask again for just the branch you want.
scoped = client.extract_embedded_state(
url='https://example.com/products/widget',
path='next_data.props.pageProps.product',
)
print(scoped.data['bytes'], 'bytes')
print(scoped.data['data'])响应示例
{ "success": true, "data": { "url": "https://example.com/products/widget", "found": [ { "name": "next_data", "variable": "__NEXT_DATA__", "bytes": 412880 } ], "path": null, "bytes": 412893, "data": { "next_data": { "buildId": "KfC_3GF1zuM", "props": { "pageProps": { "product": { "sku": "WID-9001", "price": 149.99, "currency": "USD", "inStock": true } } } } }, "warnings": [ "Result is 412893 bytes; \"next_data\" alone is 412880. Re-run with path to scope it, e.g. path:\"next_data.props\"." ] }, "credits_used": 2, "credits_remaining": 998, "processing_time": 980}data.found页面上的每一个状态来源,包含读取自的原始对象及其序列化大小data.path所应用的路径;返回完整负载时为 nulldata.bytes所返回内容的序列化大小——给出 path 时即为缩小后的大小data.data状态本身,按来源名称索引data.warnings存在但无法按 JSON 解析的来源,以及建议使用 path 的大小提示错误处理
路径无法解析 (400 Bad Request)
path 在所提取的状态中不存在。消息会指出中断的位置以及该处可用的键,因此拼写错误可以直接修正。不扣除 credits。先不带 path 调用一次,即可看到页面实际携带的内容。
被 robots.txt 阻止 (403 Forbidden)
目标站点的 robots.txt 禁止 CrawlForge 访问此路径。如果您与目标站点另有协议,可设置 respect_robots: false 覆盖——该覆盖会记录在您的 API key 上。此覆盖对 CrawlForge 永久排除名单上的主机无效,无论 respect_robots 取何值都会被拒绝。
响应过大 (413 Payload Too Large)
页面 HTML 超过 25MB 的响应体上限。该上限针对服务端返回的页面本身,而非从中提取的状态。不收取任何费用。
目标未响应 (504 Gateway Timeout)
站点未在 timeout 内响应。状态密集的页面体积很大;在判定为失败之前,请先把 timeout 调高至 60000 的上限。不收取任何费用。