主题
信息提取工具
本文引用的源码文件
本文引用的文件
目录
引言
本文件面向“信息提取工具”的技术文档,聚焦网页内容读取、结构化数据解析、表单与链接收集、元数据与结构化数据抽取、Shadow DOM 穿透以及搜索高亮等能力。该工具以 Chrome 扩展 Content Script 为核心运行环境,通过统一的 message 路由暴露给 background 侧工具调用,最终形成可扩展的信息提取管线。
项目结构
信息提取相关代码主要位于 content 层:
page-extract.js:元数据、链接、表单、图片、Markdown/JSON 转换、iframe 内容、页面搜索。shadow-dom-utils.js:Shadow DOM 与 iframe 的深度查询、文本/HTML 获取、选择范围处理。page-tools.js:纯文本/富文本获取、表格提取、剪贴板、悬停、文本高亮等基础工具。index.js:Content Script 入口,统一消息路由,将上层工具映射到具体实现。browser-tools.js:background 侧对外暴露的工具定义(如page_content、extract_data、search_in_page、iframe_content)。
graph TB subgraph "Background 工具" BT["browser-tools.js<br/>工具定义"] end subgraph "Content Script" CI["index.js<br/>消息路由"] PT["page-tools.js<br/>基础工具"] PE["page-extract.js<br/>提取逻辑"] SDU["shadow-dom-utils.js<br/>Shadow DOM/iframe 穿透"] end BT --> CI CI --> PT CI --> PE PE --> SDU PT --> SDU
图表来源
- src/background/tools/browser-tools.js#L230-L379
- src/content/index.js#L91-L181
- src/content/page-tools.js#L1-L51
- src/content/page-extract.js#L1-L6
- src/content/shadow-dom-utils.js#L1-L11
章节来源
- src/content/index.js#L1-L391
- src/content/page-tools.js#L1-L329
- src/content/page-extract.js#L1-L817
- src/content/shadow-dom-utils.js#L1-L443
- src/background/tools/browser-tools.js#L230-L379
核心组件
- 纯文本与富文本获取
- 纯文本:基于 Shadow DOM 穿透的
deepGetText,支持 iframe 同源内容合并。 - 富文本:基于
deepGetHtml获取完整 HTML,可剥离样式;选区富文本通过 Range 克隆节点生成。
- 纯文本:基于 Shadow DOM 穿透的
- 表格数据解析
- 单表提取:
extractTable支持 JSON/Markdown 输出,可选是否包含表头行。 - 多表结构化:
pageToJson批量提取多个 table、ul/ol 列表、JSON-LD、article、Microdata。
- 单表提取:
- 链接与表单
- 链接:
extractLinks支持内/外链过滤、可选图片链接纳入。 - 表单:
extractForms识别 input/textarea/select,记录 name/id/type/placeholder/required/selector。
- 链接:
- 元数据与结构化数据
- 元数据:
extractMetadata提取 title/description/keywords/author、Open Graph、Twitter Card、canonical、JSON-LD、Microdata。
- 元数据:
- Shadow DOM 穿透
- 深度查询、文本/HTML 获取、选择范围、视口坐标计算、监听器管理。
- 页面搜索与高亮
searchInPage支持 plain/regex 模式、大小写敏感、上下文片段、结果高亮。
章节来源
- src/content/page-tools.js#L53-L186
- src/content/page-extract.js#L31-L126
- src/content/page-extract.js#L131-L264
- src/content/page-extract.js#L351-L600
- src/content/shadow-dom-utils.js#L12-L232
- src/content/page-extract.js#L668-L816
架构总览
信息提取在 MV3 双进程架构中的调用路径如下:
- Background 工具定义
extract_data、page_content、search_in_page、iframe_content等。 - Background 通过 chrome.runtime 向 Content Script 发送消息。
- Content Script 的
index.js根据 message.type 分发到对应处理器。 - 处理器调用
page-extract.js或page-tools.js的具体函数。 - 底层依赖
shadow-dom-utils.js完成跨 Shadow DOM/iframe 的访问。
sequenceDiagram
participant BG as "Background<br/>browser-tools.js"
participant CS as "Content Script<br/>index.js"
participant EX as "page-extract.js"
participant PT as "page-tools.js"
participant SDU as "shadow-dom-utils.js"
BG->>CS : 发送消息 {type, params}
CS->>CS : 查找 HANDLERS[type]
alt 类型=EXTRACT_METADATA/EXTRACT_LINKS/EXTRACT_FORMS/EXTRACT_IMAGES/SEARCH_IN_PAGE/IFRAME_CONTENT
CS->>EX : 调用对应提取函数
EX->>SDU : deepQuerySelector/deepGetText/deepGetHtml
SDU-->>EX : 返回元素/文本/HTML
EX-->>CS : 返回结构化结果
else 类型=GET_PAGE_TEXT/GET_FULL_HTML/EXTRACT_TABLE
CS->>PT : 调用基础工具
PT->>SDU : 使用 Shadow DOM 穿透
SDU-->>PT : 返回内容
PT-->>CS : 返回结果
end
CS-->>BG : sendResponse(结果)
图表来源
- src/background/tools/browser-tools.js#L230-L379
- src/content/index.js#L91-L181
- src/content/page-extract.js#L31-L816
- src/content/page-tools.js#L53-L186
- src/content/shadow-dom-utils.js#L12-L232
详细组件分析
纯文本与富文本获取
- 纯文本
- 通过
getPageText调用deepGetText,自动合并 Shadow DOM 与同源 iframe 文本,并截取最大长度。 - 可选择包含标题和链接摘要,便于快速概览。
- 通过
- 富文本
getFullHtml基于deepGetHtml获取完整 HTML,可按需移除 style 属性以减少体积。getSelectedContent支持 text/html 两种格式,html 模式下通过 Range.cloneContents 保留富文本结构。
flowchart TD
Start(["调用 getPageText/getFullHtml"]) --> Mode{"格式?"}
Mode --> |text| GetText["deepGetText()"]
Mode --> |html| GetHtml["deepGetHtml()"]
GetText --> Clean["截断 maxLength / 统计词数"]
GetHtml --> StripStyle{"是否去除样式?"}
StripStyle --> |是| RemoveStyle["移除 style 属性"]
StripStyle --> |否| KeepStyle["保留样式"]
Clean --> Return["返回结构化结果"]
RemoveStyle --> Return
KeepStyle --> Return
图表来源
章节来源
表格数据解析
- 单表提取
extractTable- 支持 selector 定位表格,遍历 tr/td/th 提取单元格文本。
- 支持 includeHeaders 控制是否包含首行作为表头。
- 输出格式:json(含 data、rowCount、columnCount)或 markdown(标准表格语法)。
- 多表结构化
pageToJson- 批量扫描 root 下的 table、ul/ol、JSON-LD、article、Microdata。
- 对每个 table 提取 headers 与 rows,限制 maxItems 避免过大结果。
- 对 Microdata 去重(按 itemType + 前缀文本签名),避免重复条目。
flowchart TD
TStart(["extractTable/pageToJson"]) --> Locate["定位表格/根节点"]
Locate --> Rows["遍历 tr 行"]
Rows --> Cells["遍历 td/th 单元格"]
Cells --> BuildRow["构建行数据"]
BuildRow --> Format{"输出格式?"}
Format --> |json| JsonOut["JSON: data/rowCount/columnCount"]
Format --> |markdown| MdOut["Markdown: 表头+分隔符+数据行"]
JsonOut --> TReturn["返回结果"]
MdOut --> TReturn
图表来源
章节来源
链接与表单提取
- 链接
extractLinks- 遍历 a[href],过滤 javascript:/# 协议,判断内外域。
- 可选 includeImages 将 img[src] 作为 type=image 的链接项加入。
- 表单
extractForms- 支持 formSelector 限定单个表单,否则遍历所有 form。
- 字段类型:input/textarea/select,记录 name/id/type/placeholder/required/selector。
- select 额外收集 options[value,text]。
flowchart TD
LStart(["extractLinks/extractForms"]) --> Type{"类型?"}
Type --> |links| ScanA["遍历 a[href]"]
Type --> |forms| ScanF["遍历 form/input/textarea/select"]
ScanA --> Filter["过滤协议/内外域"]
ScanF --> Fields["收集字段属性"]
Filter --> LReturn["返回 links 数组"]
Fields --> FReturn["返回 forms 数组"]
图表来源
章节来源
元数据与结构化数据
- 元数据
extractMetadata- 标题、描述、关键词、作者。
- Open Graph:og:title/description/image/url/type/site_name/locale。
- Twitter Card:card/title/description/image/site/creator。
- Canonical URL。
- JSON-LD:解析 script[type="application/ld+json"],兼容 @graph 数组。
- Microdata:itemscope/itemprop 递归收集,避免嵌套 itemscope 重复。
- 结构化 JSON
pageToJson- 同时提取 tables/lists/jsonLd/articles/microdata,并给出 counts。
classDiagram
class MetadataExtractor {
+extractMetadata() Object
+pageToJson(selector, maxItems) Object
}
class JSONLDParser {
+parseScripts() Array
}
class MicrodataCollector {
+collectItemscope() Array
}
MetadataExtractor --> JSONLDParser : "解析 ld+json"
MetadataExtractor --> MicrodataCollector : "收集 itemscope"
图表来源
章节来源
Shadow DOM 穿透技术
- 深度查询
deepQuerySelector/deepQuerySelectorAll优先遍历 shadowRoot 与 iframe,再回退到当前 root 的 query。- 支持 maxDepth 防止无限递归,visited 集合防止循环引用。
- 文本/HTML 获取
deepGetText合并 body.innerText 与 shadow tree textContent,拼接 iframe 内容。deepGetHtml合并 documentElement.outerHTML 与 shadow innerHTML,插入注释标记区分来源。
- 选择范围与视口坐标
deepGetSelection递归查找有焦点 frame 的选择范围。getElementViewportPosition/getRangeViewportPosition累加 iframe 偏移,确保坐标正确。
- 监听器管理
attachSelectionListeners/removeSelectionListeners为各 Shadow Root 注册 selectionchange。
flowchart TD
SStart(["Shadow DOM 操作"]) --> Traverse["遍历 * 元素"]
Traverse --> CheckSR{"存在 shadowRoot?"}
CheckSR --> |是| RecurseSR["递归进入 shadowRoot"]
CheckSR --> |否| CheckIF{"存在 iframe/frame?"}
CheckIF --> |是| RecurseIF["递归进入 iframeDoc"]
CheckIF --> |否| QueryCurrent["在当前 root 执行 query"]
RecurseSR --> Merge["合并结果"]
RecurseIF --> Merge
QueryCurrent --> Merge
Merge --> SReturn["返回元素/文本/HTML/坐标"]
图表来源
- src/content/shadow-dom-utils.js#L12-L86
- src/content/shadow-dom-utils.js#L135-L232
- src/content/shadow-dom-utils.js#L311-L377
- src/content/shadow-dom-utils.js#L388-L423
章节来源
页面搜索与高亮
searchInPage- plain 模式:使用 window.find 辅助定位,TreeWalker 遍历文本节点匹配正则。
- regex 模式:直接对 body.innerText 执行正则匹配,支持大小写敏感。
- 支持 contextLength 提供命中前后上下文,maxResults 限制结果数量。
- highlight=true 时,通过 Range 包裹命中文本节点,避免替换 innerHTML 导致事件丢失。
flowchart TD
SearchStart(["searchInPage"]) --> Validate{"query/pattern 是否存在?"}
Validate --> |否| Error["返回错误:缺少关键词"]
Validate --> |是| Mode{"mode?"}
Mode --> |plain| Plain["window.find + TreeWalker 匹配"]
Mode --> |regex| Regex["RegExp.exec(bodyText)"]
Plain --> Context["构造上下文片段"]
Regex --> Context
Context --> Highlight{"highlight?"}
Highlight --> |是| WrapRange["Range 包裹命中文本节点"]
Highlight --> |否| SkipHighlight["跳过高亮"]
WrapRange --> Return["返回 matches/highlighted"]
SkipHighlight --> Return
图表来源
章节来源
iframe 内容获取
getIframeContent- 遍历指定 selector 的 iframe,尝试访问 contentDocument/contentWindow.document。
- 若同源且可访问,则读取 title、textContent、htmlLength。
- 支持 includeNested 递归处理嵌套 iframe(默认深度限制为 2)。
- 不可访问时仍返回基本信息(url、accessible=false)。
sequenceDiagram participant Caller as "调用方" participant API as "getIframeContent" participant IF as "iframe 元素" participant Doc as "iframe.contentDocument" Caller->>API : 传入 selector/includeNested/maxLength API->>IF : querySelectorAll(selector) loop 每个 iframe API->>Doc : 尝试访问 contentDocument alt 可访问 Doc-->>API : title/textContent/htmlLength API->>API : 递归处理嵌套 iframe else 不可访问 Doc-->>API : 抛出异常 API->>API : accessible=false end end API-->>Caller : 返回 iframes 列表与统计
图表来源
章节来源
依赖关系分析
- Content Script 入口
index.js维护 HANDLERS Map,O(1) 查找消息处理器。 - TOP_FRAME_ONLY_TYPES 确保某些工具只在顶层 frame 响应,避免 iframe 抢先应答。
- ASYNC_HANDLERS 标记异步处理器,保持消息通道开放直到 Promise resolve。
- 工具定义在
browser-tools.js,明确 dataType、format、filterType 等参数契约。
graph LR BT["browser-tools.js<br/>工具定义"] --> CI["index.js<br/>HANDLERS/TOP_FRAME_ONLY_TYPES/ASYNC_HANDLERS"] CI --> PT["page-tools.js"] CI --> PE["page-extract.js"] PT --> SDU["shadow-dom-utils.js"] PE --> SDU
图表来源
章节来源
性能与优化建议
- 控制结果规模
- 使用
maxItems/maxResults/maxLength限制返回体量,避免大页面导致内存与传输压力。
- 使用
- 减少 DOM 遍历开销
- 优先使用具体 selector 缩小范围,避免全页遍历。
- 对 Shadow DOM/iframe 设置合理 maxDepth,避免深层树遍历。
- 避免重复工作
- 使用 seenUrls/seenJsonLd/seenMicrodata 去重,减少冗余解析。
- 安全与稳定性
- 对跨域 iframe 捕获异常并跳过,保证主流程稳定。
- 高亮采用 Range 包裹文本节点,不替换 innerHTML,避免事件丢失与布局抖动。
- 输出格式选择
- 表格输出优先 JSON 用于程序处理,Markdown 用于人类阅读;按需选择。
[本节为通用指导,不直接分析具体文件]
故障排查指南
- 未找到目标元素
- 检查 selector 是否正确,必要时使用
generateUniqueSelector生成稳定选择器。 - 确认是否在顶层 frame 调用需要 TOP_FRAME_ONLY_TYPES 的工具。
- 检查 selector 是否正确,必要时使用
- 跨域 iframe 不可访问
- getIframeContent 会返回 accessible=false,这是预期行为;仅同源 iframe 可读取内容。
- 搜索无结果
- 确认 query/pattern 非空,plain/regex 模式差异;注意大小写敏感选项。
- 高亮无效
- 确保 highlight=true 且存在匹配;Range 高亮不会破坏事件监听。
- 表单字段缺失
- 确认字段为 input/textarea/select;动态生成的字段需在渲染后再次提取。
章节来源
- src/content/page-extract.js#L31-L126
- src/content/page-extract.js#L668-L816
- src/content/page-tools.js#L151-L186
结论
信息提取工具以 Content Script 为中心,结合 Shadow DOM 穿透与 iframe 同源访问,提供了从纯文本、富文本到结构化数据的完整提取能力。通过统一的 message 路由与清晰的工具定义,扩展端与后台进程协作顺畅。建议在大规模页面中严格控制结果规模、合理使用 selector 与深度限制,并遵循安全最佳实践以避免跨域与事件丢失问题。
[本节为总结性内容,不直接分析具体文件]