1
0

创建 lyxy-reader-html skill

- 新增 skill: lyxy-reader-html,用于解析 HTML 文件和 URL 网页内容
- 支持 URL 下载(pyppeteer → selenium → httpx → urllib 优先级回退)
- 支持 HTML 解析(trafilatura → domscribe → MarkItDown → html2text 优先级回退)
- 支持查询功能:全文提取、字数统计、行数统计、标题提取、章节提取、正则搜索
- 新增 spec: html-document-parsing
- 归档 change: create-lyxy-reader-html-skill
This commit is contained in:
2026-03-08 02:02:03 +08:00
parent 0bd9ec8a36
commit 6b4fcf2647
16 changed files with 1827 additions and 3 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-03-07

View File

@@ -0,0 +1,124 @@
## Context
当前项目已有 `lyxy-reader-office` skill 用于解析办公文档,其架构设计成熟,包含统一命令行入口、多解析器回退机制、多功能查询等特性。现在需要创建 `lyxy-reader-html` skill功能上类似但针对 HTML 内容,同时需支持 URL 下载能力。
**约束条件**
-`lyxy-reader-office` 保持相同的用户体验(参数、输出格式)
- 代码完全独立,不复用 `lyxy-reader-office` 的代码
- 参考 `temp/downloader/download.py``temp/parser/parse.py` 的现有实现
## Goals / Non-Goals
**Goals:**
- 创建完整的 `lyxy-reader-html` skill 目录结构
- 实现统一的命令行入口 `parser.py`,支持 URL 和 HTML 文件输入
- 实现下载器模块,按 pyppeteer → selenium → httpx → urllib 优先级回退
- 实现解析器模块,按 trafilatura → domscribe → MarkItDown → html2text 优先级回退
- 实现 HTML 预处理清理和 Markdown 后处理
- 实现与 `lyxy-reader-office` 一致的查询功能(全文、字数、行数、标题、章节、搜索)
**Non-Goals:**
- 不支持可配置的 HTML 清理选项
- 不支持 JavaScript 渲染开关(默认启用完整下载链)
- 不支持正文/全文切换(默认使用解析器的正文提取)
## Decisions
### 1. 目录结构参考 lyxy-reader-office
**决策**:采用与 `lyxy-reader-office` 相同的目录结构
```
lyxy-reader-html/
├── SKILL.md
├── scripts/
│ ├── parser.py # 统一入口
│ ├── common.py # 公共函数
│ ├── downloader.py # URL 下载
│ ├── html_parser.py # HTML 解析
│ └── README.md
└── references/
├── examples.md
├── parsers.md
└── error-handling.md
```
**理由**:保持项目一致性,降低用户学习成本
---
### 2. 下载器优先级pyppeteer → selenium → httpx → urllib
**决策**:直接采用 `temp/downloader/download.py` 的优先级顺序
- pyppeteer支持 JS 渲染)
- selenium支持 JS 渲染,作为 pyppeteer 的备选)
- httpx轻量级 HTTP 客户端)
- urllib标准库兜底
**备选方案考虑**
- httpx → urllib → pyppeteer → selenium速度优先
- 选择保持原顺序,因为 JS 渲染能力对许多现代网页很重要
---
### 3. 解析器优先级trafilatura → domscribe → MarkItDown → html2text
**决策**:采用精简后的 4 个解析器,顺序参考 `temp/parser/parse.py`
1. trafilatura - 专门用于网页正文提取,质量高
2. domscribe - 专注内容提取
3. MarkItDown - 微软官方,格式规范
4. html2text - 经典库,作为兜底
**备选方案考虑**
- 保留原 6 个解析器(增加 markdownify 和 html-to-markdown
- 选择精简为 4 个,减少维护复杂度
---
### 4. HTML 预处理清理默认开启且不可配置
**决策**:解析前固定执行 HTML 清理,移除 script/style/link/svg 标签和 URL 属性
- 使用 `temp/clean_html.py` 的清理逻辑
- 不提供 `--no-clean` 参数
**理由**:简化设计,减少用户选择负担
---
### 5. Markdown 处理函数独立实现
**决策**:在 `common.py` 中独立实现以下函数,不复用 `lyxy-reader-office`
- `remove_markdown_images()` - 移除图片标记
- `normalize_markdown_whitespace()` - 规范化空行
- `extract_titles()` - 提取标题
- `extract_title_content()` - 提取章节内容
- `search_markdown()` - 正则搜索
**理由**:保持 skill 之间完全隔离
---
### 6. 命令行参数与 lyxy-reader-office 保持一致
**决策**:支持以下参数,与 `lyxy-reader-office` 完全一致:
- (无参数):全文输出
- `-c` / `--count`:字数统计
- `-l` / `--lines`:行数统计
- `-t` / `--titles`:提取标题
- `-tc <name>` / `--title-content <name>`:提取章节
- `-s <pattern>` / `--search <pattern>`:正则搜索
- `-n <num>` / `--context <num>`:搜索上下文行数
**不添加** HTML 专用参数
**理由**:统一用户体验
## Risks / Trade-offs
| 风险 | 影响 | 缓解措施 |
|------|------|----------|
| pyppeteer/selenium 依赖重,安装困难 | 中 | 提供 httpx/urllib 作为轻量备选 |
| trafilatura 可能提取不到正文 | 低 | 后续解析器会继续尝试 |
| 不同解析器输出质量差异大 | 中 | 用户可通过安装不同依赖来间接选择解析器 |
| URL 下载超时或被反爬 | 中 | 多下载器回退增加成功率 |
## Migration Plan
不适用 - 这是新 skill 创建,无迁移需求。
## Open Questions
无 - 所有决策已明确。

View File

@@ -0,0 +1,26 @@
## Why
当前已有 `lyxy-reader-office` skill 用于解析办公文档,但缺少对 HTML 网页内容的解析能力。用户需要从 URL 或本地 HTML 文件中提取内容并转换为 Markdown 格式,同时支持标题提取、内容搜索等查询功能。
## What Changes
- 创建新 skill `lyxy-reader-html`,目录结构参考 `lyxy-reader-office`
- 实现命令行工具 `scripts/parser.py`,接受 URL 或 HTML 文件作为输入
- URL 模式下按优先级尝试下载器pyppeteer → selenium → httpx → urllib
- HTML 解析按优先级尝试trafilatura → domscribe → MarkItDown → html2text
- 支持 HTML 预处理清理(移除 script/style/link 等标签和 URL 属性)
- 实现查询功能:全文输出、字数统计、行数统计、标题提取、章节提取、正则搜索
## Capabilities
### New Capabilities
- `html-document-parsing`: HTML 文档和 URL 内容解析能力,将 HTML 转换为 Markdown 并支持多种查询模式
### Modified Capabilities
(无)
## Impact
- 新增目录 `skills/lyxy-reader-html/`
- 新增 Python 脚本依赖trafilatura、domscribe、markitdown、html2text、httpx、pyppeteer、selenium、beautifulsoup4
- 与现有 skill 完全隔离,不影响其他功能

View File

@@ -0,0 +1,137 @@
## ADDED Requirements
### Requirement: 优先使用 lyxy-reader-html 解析 HTML 内容
大模型在遇到 URL、.html 或 .htm 文件时SHALL 优先激活并使用 lyxy-reader-html skill 来读取内容。
#### Scenario: 用户请求读取 URL
- **WHEN** 用户提供以 http:// 或 https:// 开头的 URL
- **THEN** 大模型 SHALL 激活 lyxy-reader-html skill
- **AND** 使用 skill 目录下的 `scripts/parser.py` 执行解析
#### Scenario: 用户请求读取 HTML 文件
- **WHEN** 用户提供的文件路径以 .html 或 .htm 结尾
- **THEN** 大模型 SHALL 激活 lyxy-reader-html skill
- **AND** 使用 skill 目录下的 `scripts/parser.py` 执行解析
### Requirement: 必须通过 lyxy-runner-python 执行脚本
当环境中存在 lyxy-runner-python skill 时,大模型 SHALL 必须使用该 skill 来运行 parser.py 脚本。
#### Scenario: lyxy-runner-python 可用
- **WHEN** 大模型环境中存在 lyxy-runner-python skill
- **THEN** 大模型 SHALL 通过 lyxy-runner-python skill 执行 parser.py
- **AND** 利用 lyxy-runner-python 的自动依赖管理功能uv安装所需的 Python 包
#### Scenario: lyxy-runner-python 不可用
- **WHEN** 大模型环境中不存在 lyxy-runner-python skill
- **THEN** 大模型 SHALL 降级到直接使用 Python 执行 parser.py
- **AND** 提示用户当前使用直接执行模式
- **AND** 禁止自动执行 pip install 安装依赖
### Requirement: 引导阅读 README 获取详细用法
大模型在需要了解 parser.py 的详细使用方式时SHALL 阅读 `scripts/README.md` 文件。
#### Scenario: 首次使用 skill 执行解析
- **WHEN** 大模型首次使用 lyxy-reader-html skill 或不确定具体参数用法
- **THEN** 大模型 SHALL 阅读 `scripts/README.md` 获取命令行参数、依赖安装和使用示例等详细信息
#### Scenario: 遇到特殊参数需求
- **WHEN** 用户请求使用特殊功能(如章节提取、正则搜索等)
- **THEN** 大模型 SHALL 参考 `scripts/README.md` 中的对应参数说明
### Requirement: 支持 URL 和 HTML 文件两种输入源
系统 SHALL 支持从 URL 下载 HTML 内容或直接读取本地 HTML 文件两种输入方式。
#### Scenario: 输入为 URL
- **WHEN** 输入以 http:// 或 https:// 开头
- **THEN** 系统 SHALL 识别为 URL 模式
- **AND** 尝试下载 URL 对应的 HTML 内容
#### Scenario: 输入为本地 HTML 文件
- **WHEN** 输入是存在的本地文件且扩展名为 .html 或 .htm
- **THEN** 系统 SHALL 识别为 HTML 文件模式
- **AND** 直接读取文件内容进行解析
#### Scenario: 输入无法识别
- **WHEN** 输入既不是 URL 也不是有效的 HTML 文件
- **THEN** 系统 SHALL 输出错误信息
- **AND** 以退出码 1 退出
### Requirement: URL 下载器按优先级降级
系统 SHALL 按 pyppeteer → selenium → httpx → urllib 的优先级尝试下载 URL 内容。
#### Scenario: 下载器按优先级降级
- **WHEN** 优先级最高的下载器不可用或下载失败
- **THEN** 系统自动尝试下一优先级的下载器
- **AND** 记录每个下载器的失败原因
#### Scenario: 所有下载器失败
- **WHEN** 所有下载策略均失败
- **THEN** 系统返回详细的失败信息
- **AND** 列出每种下载策略的失败原因
- **AND** 以退出码 1 退出
### Requirement: HTML 解析器按优先级降级
系统 SHALL 按 trafilatura → domscribe → MarkItDown → html2text 的优先级尝试解析 HTML 内容。
#### Scenario: 解析器按优先级降级
- **WHEN** 优先级最高的解析器不可用或解析失败
- **THEN** 系统自动尝试下一优先级的解析器
- **AND** 记录每个解析器的失败原因
#### Scenario: 所有解析器失败
- **WHEN** 所有解析策略均失败
- **THEN** 系统返回详细的失败信息
- **AND** 列出每种解析策略的失败原因
- **AND** 以退出码 1 退出
### Requirement: HTML 内容预处理清理
系统 SHALL 在解析前对 HTML 内容进行预处理清理,移除噪声元素。
#### Scenario: 清理 script 和 style 标签
- **WHEN** HTML 内容包含 &lt;script&gt;、&lt;style&gt;、&lt;link&gt;、&lt;svg&gt; 标签
- **THEN** 系统 SHALL 移除这些标签及其内容
#### Scenario: 清理 URL 属性
- **WHEN** HTML 标签包含 href、src、srcset、action、data-*src 等 URL 属性
- **THEN** 系统 SHALL 移除这些属性
#### Scenario: 清理 style 属性
- **WHEN** HTML 标签包含 style 属性
- **THEN** 系统 SHALL 移除 style 属性
### Requirement: 支持统一的查询功能
系统 SHALL 提供统一的查询接口,包括全文提取、元数据查询、标题提取、章节提取和正则搜索。
#### Scenario: 获取文档字数
- **WHEN** 用户请求获取文档的字数
- **THEN** 系统使用 `-c` 参数返回文档的总字符数
#### Scenario: 获取文档行数
- **WHEN** 用户请求获取文档的行数
- **THEN** 系统使用 `-l` 参数返回文档的总行数
#### Scenario: 提取所有标题
- **WHEN** 用户请求提取文档的标题结构
- **THEN** 系统使用 `-t` 参数返回所有 1-6 级标题
#### Scenario: 提取指定章节内容
- **WHEN** 用户请求提取特定标题名称的章节内容
- **THEN** 系统使用 `-tc` 参数返回该章节的完整内容
- **AND** 包含完整的上级标题链和所有下级内容
#### Scenario: 正则表达式搜索
- **WHEN** 用户请求在文档中搜索关键词或模式
- **THEN** 系统使用 `-s` 参数返回所有匹配结果及上下文
- **AND** 默认包含前后各 2 行非空行上下文
- **AND** 支持 `-n` 参数自定义上下文行数
### Requirement: Markdown 后处理
系统 SHALL 对解析后的 Markdown 内容进行后处理,提升可读性。
#### Scenario: 移除图片标记
- **WHEN** 解析结果包含 Markdown 图片语法 `![alt](url)`
- **THEN** 系统 SHALL 移除这些图片标记
#### Scenario: 规范化空行
- **WHEN** 解析结果包含连续 3 个或更多空行
- **THEN** 系统 SHALL 将其合并为单个空行

View File

@@ -0,0 +1,58 @@
## 1. 初始化 Skill 目录结构
- [x] 1.1 创建 `skills/lyxy-reader-html/` 目录
- [x] 1.2 创建 `skills/lyxy-reader-html/scripts/` 子目录
- [x] 1.3 创建 `skills/lyxy-reader-html/references/` 子目录
## 2. 创建 SKILL.md 主文档
- [x] 2.1 编写 YAML 前置元数据name、description、compatibility
- [x] 2.2 编写 Purpose 章节
- [x] 2.3 编写 When to Use 章节(含触发词)
- [x] 2.4 编写 Quick Reference 章节(参数表)
- [x] 2.5 编写 Workflow 章节
- [x] 2.6 编写 References 章节
## 3. 实现 common.py 公共模块
- [x] 3.1 实现 HTML 清理函数 `clean_html_content()`
- [x] 3.2 实现 Markdown 图片移除函数 `remove_markdown_images()`
- [x] 3.3 实现 Markdown 空行规范化函数 `normalize_markdown_whitespace()`
- [x] 3.4 实现标题级别检测函数 `get_heading_level()`
- [x] 3.5 实现标题提取函数 `extract_titles()`
- [x] 3.6 实现章节内容提取函数 `extract_title_content()`
- [x] 3.7 实现正则搜索函数 `search_markdown()`
## 4. 实现 downloader.py URL 下载模块
- [x] 4.1 实现 `download_with_pyppeteer()` 函数
- [x] 4.2 实现 `download_with_selenium()` 函数
- [x] 4.3 实现 `download_with_httpx()` 函数
- [x] 4.4 实现 `download_with_urllib()` 函数
- [x] 4.5 实现统一的 `download_html()` 入口函数,按优先级尝试各下载器
## 5. 实现 html_parser.py HTML 解析模块
- [x] 5.1 实现 `parse_with_trafilatura()` 函数
- [x] 5.2 实现 `parse_with_domscribe()` 函数
- [x] 5.3 实现 `parse_with_markitdown()` 函数
- [x] 5.4 实现 `parse_with_html2text()` 函数
- [x] 5.5 实现统一的 `parse_html()` 入口函数,按优先级尝试各解析器
## 6. 实现 parser.py 命令行入口
- [x] 6.1 实现命令行参数解析argparse
- [x] 6.2 实现输入源判断URL / HTML 文件)
- [x] 6.3 实现 URL 下载流程(如需要)
- [x] 6.4 实现 HTML 清理流程
- [x] 6.5 实现 HTML 解析流程
- [x] 6.6 实现 Markdown 后处理(移除图片、规范化空行)
- [x] 6.7 实现各查询模式(全文、字数、行数、标题、章节、搜索)
- [x] 6.8 实现错误处理和退出码
## 7. 创建参考文档
- [x] 7.1 创建 `scripts/README.md` 详细使用文档
- [x] 7.2 创建 `references/examples.md` 使用示例
- [x] 7.3 创建 `references/parsers.md` 解析器说明
- [x] 7.4 创建 `references/error-handling.md` 错误处理指南