# 网页正文整理 ## 使用方式 动态网页提取默认使用 `controls.mode: organize`,将同一 URL 的多份提取结果整理成一份带来源的正文。静态 HTTP 和 AIHOT 专用 API 保持各自原始格式。旧版兼容模式为 `select`,可在设置页切换,保存后下一次调用生效。 整理不调用语言模型,不改写原文,不推断遗漏事实,也不把多份提取当作事实交叉验证。服务来源表示哪个提取器返回了内容,同一页面的复制结果不能证明内容真实。 ## 输出结构 | 部分 | 内容 | | --- | --- | | 主正文 | 按章节、共同内容块对齐后的去重内容,保留原文内部重复 | | 补充片段 | 独有章节,或标题、明确版本标记、语言、目标、共同锚点不一致的独立片段 | | 不兼容提取摘要 | 多路标题、版本或语言不一致,或此类内容块过多时,仅记录服务、块数与来源;不再重复整份正文 | | 文本差异 | 可对齐的数字/否定词变体或段落顺序差异,保留原文和来源 | | 提取来源与处理说明 | 服务 ID、返回 URL、状态、接收时间、上游截断、失败及预算说明 | 内容块后的 `F1:B2` 表示第一份提取的第二个原始内容块。多份完全相同的内容块会共用来源标记;同一份原文中重复出现的警告或段落仍保留。 例如两份正文分别提供说明和表格,共同简介只保留一次,说明与表格同时保留。若相同位置出现「价格 100 元」和「价格 120 元」,两份原文放入差异部分,插件不平均、不选定价格。 ## 整理规则与限制 HTML 使用 Turndown 与 GFM 表格支持转换为 Markdown,不执行脚本,并移除导航、选择框和按钮。Markdown 仅清理明确的导航目录、面包屑及主题控件;正文中的「Navigation」标题、普通链接列表、代码、表格和引用保留。处理说明记录移除的内容块数量。 标题比较忽略页内定位符;普通段落的空白、加粗与行内代码格式归一化只用于比较,输出保留原文。不同章节中至少 32 字符的相同内容块也可跨服务合并来源;同一份提取内的重复次数保留。链接目标、数字和否定词不同的段落不会因此被视为相同内容。标题、代码围栏、缩进代码、表格、列表和引用分别作为内容块处理。 章节按标题路径及出现次数对齐,按共同内容块定位补充位置。排列参照优先使用同标题且章节较完整的正常正文;它只提供排列顺序,不决定内容真伪。段落中的 `Version:`、`版本:`、`文档版本:` 标记不同,也会隔离为独立片段;没有明确标记时无法可靠判断页面版本。不同返回 URL(仅忽略锚点)的内容不混入主正文。唯一的协议升级例外是同主机、同路径和同查询参数、默认端口且不含用户信息的 HTTP → HTTPS;选择正常的 HTTPS 正文后,原 HTTP 内容按不同目标隔离,输出 URL 使用最终地址。跨站、路径/查询变化、非默认端口和 HTTPS 降级均不属于此例外。识别出的登录/挑战页标记为不可用;只有这些页面或错误目标时返回 `WEB_PROVIDER_ERROR`,附服务 ID 和 `target-mismatch`/`login-or-challenge` 等原因,不在错误中附 URL、凭证或正文。仅目标页面的非 2xx 正文时保留状态,内容仍受整理输出预算约束并附来源。 检测到引用式链接或脚注定义时,各份提取以独立的 Markdown 代码块保留,完全相同的整份原文可合并来源。此路径不做段落互补,避免不同来源的同名定义改变链接目标或脚注含义;代码块内的链接不会直接渲染为可点击链接。 差异识别采用确定性规则,只覆盖可对齐的数字、否定词和顺序变体,不保证识别全部语义矛盾。未对齐的内容作为补充保留。登录与挑战页面识别依赖常见标题,不保证覆盖所有拦截页面。短文语言判断、非标准 Markdown、不同层级的标题以及相似但不完全相同的段落,可能产生重复或独立片段,需要使用者核对。 标题、版本或语言不一致的提取会先尝试作为独立补充保留;当多路同时不一致或累计内容块过多时,插件只输出摘要行(服务、内容块数与一个原始来源标记),避免同一网页的兼容正文被重复噪声淹没。摘要不表示该路内容错误,也不删除来源对照表中的状态;需要核对原文时可在设置页临时收窄提取服务后重取。 默认输出最多 100,000 字符,包含来源与处理说明。超过预算时省略完整内容块,设置 `truncated` 并说明省略数量。每份输入最多 1,000,000 字符、2,000 个内容块,超限返回 `WEB_FETCH_TOO_LARGE`。识别出的 JSON 对象/数组及 XML 内容原样返回,超过输出预算时报错,不裁断结构化数据。第三方服务已发生的截断无法恢复。 自动预设中,至少三家服务返回同标题、共享长段落且各有不少于 1,200 字符段落正文后,经过宽限期结束未完成渠道;不是返回第一份正文就结束。宽限内收到的补充内容仍保留。固定预设不采用此结束条件。短文、标题不同或没有共同段落时继续按原预算等待。具体时长见[调用范围与预算](./configuration.md)。 提前结束、单路超时或操作到期导致结果可能不完整时,标记 `truncated` 并说明原因;该标记不一定表示字符预算耗尽。操作总限时到期时返回已完成正文;没有可用正文时返回 `WEB_FETCH_TIMEOUT`。调用方主动取消仍返回 `WEB_ABORTED`。 ## 可重复的离线评估 ```sh pnpm run benchmark:content ``` 脚本用同一组合成提取结果比较首份结果、旧版评分选择和正文整理。指标包括预先标记的内容保留率、共享段落出现次数、数字变体保留数及本地处理时间;脚本断言整理结果保留所有标记内容、跨服务共享段落只保留一次。 这项评估验证确定性整理规则,不调用真实服务,不代表第三方接口当前质量、网络延迟、费用或竞品表现。协议、取消、预算和原生工具集成另外由 `pnpm run check` 的本地模拟测试验证。 ## 输入与输出演示 下载或克隆仓库后,用浏览器打开 [content-demo.html](./assets/content-demo.html),可以切换示例并查看各服务输入与整理输出。页面离线运行,无需密钥;GitHub 文件预览不会执行页面脚本。全部数据见 [content-demo.json](./assets/content-demo.json)。 「Example Domain 实际提取」来自 Firecrawl、Tavily、Exa 对同一公开页面的真实响应。「说明、表格与代码互补」「三个价格变体」「长文独有章节」为合成输入,用来验证确定性规则。合成示例中的服务 ID 只标识输入,不说明对应服务真实返回了这些内容。 真实示例中,Firecrawl 返回无标题的多语言正文,Tavily 与 Exa 返回有标题的英文正文。共同正文合并来源,不同章节中满足规则的相同长段落也会去重;其他语言内容保留。演示用采集输入离线重放,因此输出里的接收时间与 HTTP 请求数不表示采集时间或采集请求数。 重新生成合成演示: ```sh pnpm run build node scripts/build-content-demo.mjs ``` 真实输入由显式提供的 `--live-capture ` 加入。生成器仅接受 `https://example.com/` 的短正文,并校验服务、状态和返回 URL,避免把任意页面内容或请求头写入公开演示。演示只展示正文处理,不调用外部接口,也不测量网络性能。