跳到正文
基础工具1 credit

extract_text

通过智能解析从 HTML 中提取干净、易读的文本。在保留主要文本内容的同时,自动移除脚本、样式和样板内容。

使用场景

为 LLM 提取文章

提取干净的文章文本,用于摘要、分析或 AI 处理

内容分析

获取纯文本用于词数统计、可读性分析或情感检测

用于摘要的干净文本

在传给摘要模型之前移除 HTML 噪声

移除样板内容

移除广告、导航等非内容元素

Endpoint

POST/api/v1/tools/extract_text
Auth Required
Free 计划 1 req/s
1 credit

Parameters

NameTypeRequiredDefaultDescription
html
stringOptional-
要从中提取文本的 HTML 内容(html 与 url 二选一)
Example: <html><body><h1>Hello World</h1></body></html>
url
stringOptional-
要抓取并从中提取文本的 URL(html 与 url 二选一)
Example: https://example.com/article
selector
stringOptional-
用于定位特定元素的 CSS 选择器(默认:整个页面)
Example: article, .content, #main
clean
booleanOptionaltrue
合并每行内的连续空格并删除空行;块元素之间的换行会保留。仅适用于 `output_format: "text"`。
Example: true
preserve_links
booleanOptionalfalse
在提取的文本之后,以 `text (href)` 的形式逐行附上每个链接。仅限 REST API(MCP 工具没有此选项),且仅适用于 `output_format: "text"`。
Example: false
preserve_formatting
booleanOptionalfalse
保留 HTML 源中的段落和标题换行。仅限 REST API(MCP 工具没有此选项),且仅适用于 `output_format: "text"`。
Example: false
max_length
numberOptional-
返回的文本或 markdown 的最大长度。超出的结果会被截断并以 `...` 结尾,同时 `data.truncated` 为 `true`;`data.truncated` 始终存在,未截断时为 `false`。
Example: 5000
output_format
stringOptionaltext
`"text"`(默认)返回 `data.text`,每个块元素一行:`<h1>Hi</h1><p>there</p>` 读作 `Hi\nthere`。`"markdown"` 则改为返回 `data.markdown`:用 Turndown 将所选元素(或 body)转换为 Markdown。两种模式下 `data` 都带有 `output_format`、`word_count` 和 `char_count`,名称与 MCP 工具一致;markdown 结果在计数时不含 Markdown 语法字符(`#`、`*`、`_`、`[`、`]` 和反引号)。`clean`、`preserve_links` 和 `preserve_formatting` 仅适用于文本模式;`max_length` 两种模式都适用。
Example: markdown
respect_robots
booleanOptionaltrue
遵守目标站点的 robots.txt。保持 `true` 时,robots.txt 对 `CrawlForge` 禁止的路径会在抓取之前以 403 拒绝,且不扣除 credits。仅在你与目标站点另有约定时才设为 `false`——此时响应会带上一条 `warnings`,并且该覆盖会记录到你的 API key 上。
Example: true
escalate
booleanOptionalfalse
选择加入:当对 `url` 的普通抓取遇到的是拦截墙而不是页面时——Cloudflare、Amazon、DataDome、PerimeterX、Akamai 或 Vercel 的挑战页、单纯的 403、429 或 444,或以 2xx 返回的空壳页面或错误占位页——自动通过 stealth 浏览器重试一次。普通抓取始终先执行;404、5xx、PDF 等二进制内容,或 `Retry-After` 等待期仍未结束的主机,永远不会触发升级;`html` 输入不会被抓取。文本从渲染出的 HTML 中提取,因此响应结构不变,另外只要设置了此参数就会带上 `escalated`,渲染实际执行时还会带上 `stealth: { engine, vendor_detected }`。升级复用与 [stealth_mode](/docs/api-reference/tools/stealth-mode) 相同的 stealth 路径和同一道 robots.txt 校验,不会新增任何针对反爬防护的处理手段;若渲染同样被拒,结果仍作为被拦截的页面返回并带有 `escalated: true`,且不计费。仅在渲染真正执行时加收 5 credits。
Example: true
escalate_engine
stringOptionalplaywright
升级阶段使用的浏览器引擎:"playwright"(默认)或 "camoufox"(基于 Firefox,抗检测能力更强;仅在后端已安装时可用)。除非 `escalate` 为 `true` 且普通抓取被拦下,否则忽略此参数。
Example: camoufox
redact_pii
boolean | objectOptionalfalse
在结果被存储或返回之前,从本次调用返回的文本中移除个人数据。 `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

抓取 URL

  • 页面只抓取一次,超时时间为 15 秒。若返回 429 或 503 且 Retry-After 不超过 10 秒,会等待该时长后再抓取一次;Retry-After 更长或缺失时不重试。
  • 可读取 HTML、XHTML、XML 及所有 text/* 类型,未带 Content-Type 的响应按 HTML 读取。PDF、图片或其他二进制内容返回 415 UNSUPPORTED_CONTENT_TYPE,附带 next_step: "process_document",且不计费:请改用 process_document 读取。
  • JSON 响应体(application/json 或 *+json)会原样放入 text 返回,并附带警告 the target returned application/json; its body is returned as text。若为 output_format: "markdown",则改为放入 markdown 返回。
  • 在客户端渲染的页面——可见文本少于 200 个字符,且含有空的 <div id="root">、"app" 或 "__next",或文本说明页面需要 JavaScript("Enable JavaScript…")——在未执行 stealth 渲染时仍返回成功,data 中带有 rendered: false,warnings 中带有 page renders client-side; use scrape,以免把空壳页面误认为内容很短的页面。html 输入同样会做此检查。

请求示例

cURL - 从 URL 提取

terminalBash
curl -X POST https://www.crawlforge.dev/api/v1/tools/extract_text \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/article",
    "selector": "article",
    "clean": true,
    "max_length": 5000
  }'

TypeScript - 从 HTML 提取

extractText.tsTypescript
// npm install crawlforge-sdk
import { CrawlForge } from 'crawlforge-sdk';

const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });

const htmlContent =
  '<html><body>' +
  '<article>' +
  '<h1>Article Title</h1>' +
  '<p>This is the main content of the article.</p>' +
  '<a href="/related">Related Article</a>' +
  '</article>' +
  '</body></html>';

const result = await client.extractText({
  html: htmlContent,
  selector: 'article',
  clean: true,
  preserve_links: true,
});

// result.data is untyped in crawlforge-sdk 0.1 — its shape is the Response Example below.
const { text, metadata } = result.data as {
  text: string; metadata: { word_count: number; character_count: number };
};
console.log('Extracted text:', text);
console.log('Word count:', metadata.word_count);
console.log('Character count:', metadata.character_count);

Python - 使用选择器提取

extract_text.pyPython
# pip install crawlforge
from crawlforge import CrawlForge

client = CrawlForge()  # reads CRAWLFORGE_API_KEY

result = client.extract_text(
    url='https://example.com/article',
    selector='article, .main-content',
    clean=True,
    preserve_formatting=True,
    max_length=10000,
)

# result.data is a plain dict — its shape is the Response Example below.
text = result.data['text']
metadata = result.data['metadata']

print(f"Title: {metadata['title']}")
print(f"Word count: {metadata['word_count']}")
print(f"Character count: {metadata['character_count']}")
print(f"\nExtracted text:\n{text[:500]}...")

响应示例

200 OK180ms
{
"success": true,
"data": {
"text": "Article Title\nThis is the main content of the article. It contains useful information that has been extracted from the HTML.\nLinks:\nRelated Article (/related)",
"output_format": "text",
"word_count": 248,
"char_count": 1432,
"truncated": false,
"metadata": {
"title": "Article Title - Example Site",
"description": "Meta description of the article",
"word_count": 248,
"character_count": 1432,
"selector_used": "article",
"links_preserved": true,
"formatting_preserved": false
}
},
"credits_used": 1,
"credits_remaining": 999,
"processing_time": 180
}
Field Descriptions
data.text提取的纯文本内容
data.output_format"text" 或 "markdown";markdown 调用返回 data.markdown 而不是 data.text
data.word_count返回文本中的词数(名称与 MCP 工具一致)
data.char_count返回文本中的字符数
data.truncatedmax_length 截断了文本时为 true(此时文本以 ... 结尾);始终存在
data.metadata.word_count提取文本中的总词数
data.metadata.character_count字符总数
data.metadata.selector_used实际应用的 CSS 选择器
credits_used本次请求扣除的 credits(每次提取 1 个)

错误处理

缺少输入(400 Bad Request)

html 和 url 都未提供。你必须至少提供其中一个。

无效选择器(400 Bad Request)

CSS 选择器无效或未匹配到任何元素。请检查选择器语法。

被反机器人拦截页阻挡(403、444 或 502)

无论 HTTP 状态码为何,目标返回的都是反机器人验证页面,而非实际内容。响应为 success: false,error.code 为 BLOCKED,附带指明 vendor(例如 cloudflare 或 akamai)及识别依据 evidence 的 blocked 对象,以及 next_step:extract_text with escalate:true, or stealth_mode operation:"scrape"。目标的状态码为 403、404、410、429、444 或 451 时原样返回,其他情况(包括以 200 返回的拦截页)均为 502。不扣除任何 credits。设置 escalate: true 时,会改为在 stealth 浏览器中渲染一次;若渲染同样被拒,同一错误会带有 escalated: true,且不带 next_step。

目标返回错误(502 Bad Gateway)

目标返回了 HTTP 错误,且未识别出反机器人拦截页。error.code 为 UPSTREAM_HTTP,消息为 Target answered HTTP <n>。403、404、410、429、444 或 451 会作为响应状态码原样透传;其他错误(5xx,或目标自身返回的 400、401)一律为 502,以免被误认为是你的请求或 API key 有问题。403、429 或 444 还会附带 next_step。不扣除任何 credits。

被 robots.txt 拦截(403 Forbidden)

目标站点的 robots.txt 对 CrawlForge 禁止了该路径。若你与目标站点另有约定,可设置 respect_robots: false 予以覆盖——该覆盖会记录到你的 API key 上。该覆盖不适用于列入 CrawlForge 永久排除名单的主机——无论 respect_robots 取何值,这类主机一律被拒绝。

不支持的内容类型(415 Unsupported Media Type)

目标返回的是 PDF、图片或其他二进制内容。error.code 为 UNSUPPORTED_CONTENT_TYPE,消息为 Unsupported content type <type>: extract_text reads HTML and text,next_step 为 process_document。不会读取响应体,不会触发升级,也不扣除任何 credits。

升级后端未配置(503 TOOL_NOT_AVAILABLE)

escalate: true 的 stealth 阶段运行在 CrawlForge 执行后端上。该后端未配置时,升级阶段返回 503,且不扣除任何 credits。

credit 费用

1 credit
每次请求 1 credit
每次文本提取花费 1 credit,与内容大小或选择器复杂度无关。设置 escalate: true 时,单次调用预估最多 6 credits,只有当普通抓取被拦下且 stealth 渲染真正执行时才加收 5 credits 的升级费用;任何失败都不计费。

相关工具