543 lines
15 KiB
Markdown
543 lines
15 KiB
Markdown
# Document Parser 使用说明
|
||
|
||
一个模块化的文档解析器,支持将 DOCX、PPTX、XLSX 和 PDF 文件转换为 Markdown 格式。
|
||
|
||
## 概述
|
||
|
||
该解析器按优先级尝试多种解析方法,确保最大兼容性:
|
||
|
||
1. **MarkItDown** (微软官方库) - 推荐使用,格式最规范
|
||
2. **python-docx / python-pptx / pandas** (成熟的 Python 库) - 输出最详细
|
||
3. **unstructured / pypdf** (成熟的 PDF 库) - PDF 专用
|
||
4. **XML 原生解析** (备选方案) - 无需依赖
|
||
|
||
### 特性
|
||
|
||
- 支持 DOCX、PPTX、XLSX 和 PDF 格式
|
||
- 自动检测文件类型和有效性
|
||
- 保留文本格式(粗体、斜体、下划线)
|
||
- 提取表格并转换为 Markdown 格式
|
||
- 提取列表并保留层级结构
|
||
- 多种输出模式(字数、行数、标题、搜索等)
|
||
- 内容过滤和规范化
|
||
- 模块化设计,易于维护和扩展
|
||
|
||
## 文件结构
|
||
|
||
```
|
||
scripts/
|
||
├── common.py # 公共函数和常量
|
||
├── docx.py # DOCX 文件解析
|
||
├── pptx.py # PPTX 文件解析
|
||
├── xlsx.py # XLSX 文件解析
|
||
├── pdf.py # PDF 文件解析
|
||
├── parser.py # 命令行入口
|
||
└── README.md # 本文档
|
||
```
|
||
|
||
## 依赖要求
|
||
|
||
### 基础运行(XML 解析)
|
||
|
||
```bash
|
||
# Python 3.6+
|
||
uv run parser.py file.docx
|
||
```
|
||
|
||
### 使用 MarkItDown
|
||
|
||
```bash
|
||
# 使用 uv 自动安装
|
||
uv run --with markitdown parser.py file.docx
|
||
uv run --with markitdown parser.py file.pptx
|
||
uv run --with markitdown parser.py file.xlsx
|
||
uv run --with "markitdown[pdf]" parser.py file.pdf
|
||
|
||
# 或手动安装
|
||
pip install markitdown
|
||
# 注意:PDF 支持需要额外安装
|
||
pip install "markitdown[pdf]"
|
||
```
|
||
|
||
### 使用专用库
|
||
|
||
```bash
|
||
# 使用 uv 自动安装
|
||
uv run --with python-docx parser.py file.docx
|
||
uv run --with python-pptx parser.py file.pptx
|
||
uv run --with pandas --with tabulate parser.py file.xlsx
|
||
uv run --with unstructured parser.py file.pdf
|
||
uv run --with pypdf parser.py file.pdf
|
||
|
||
# 或手动安装
|
||
pip install python-docx
|
||
pip install python-pptx
|
||
pip install pandas tabulate
|
||
pip install unstructured
|
||
pip install pypdf
|
||
```
|
||
|
||
### 所有依赖
|
||
|
||
```bash
|
||
# 安装所有解析库
|
||
uv run --with markitdown --with python-docx --with python-pptx --with pandas --with tabulate --with unstructured --with pypdf parser.py file.pdf
|
||
```
|
||
|
||
## 命令行用法
|
||
|
||
### 基本语法
|
||
|
||
```bash
|
||
uv run parser.py <file_path> [options]
|
||
```
|
||
|
||
### 必需参数
|
||
|
||
- `file_path`: DOCX、PPTX、XLSX 或 PDF 文件的路径(相对或绝对路径)
|
||
|
||
### 可选参数(互斥组,一次只能使用一个)
|
||
|
||
| 参数 | 短选项 | 长选项 | 说明 |
|
||
|------|---------|---------|------|
|
||
| `-c` | `--count` | 返回解析后的 markdown 文档的总字数 |
|
||
| `-l` | `--lines` | 返回解析后的 markdown 文档的总行数 |
|
||
| `-t` | `--titles` | 返回解析后的 markdown 文档的标题行(1-6级) |
|
||
| `-tc <name>` | `--title-content <name>` | 提取指定标题及其下级内容(不包含#号) |
|
||
| `-s <pattern>` | `--search <pattern>` | 使用正则表达式搜索文档,返回所有匹配结果(用---分隔) |
|
||
|
||
### 搜索上下文参数
|
||
|
||
- `-n <num>` / `--context <num>`: 与 `-s` 配合使用,指定每个检索结果包含的前后行数(默认:2)
|
||
|
||
## 使用示例
|
||
|
||
### 1. 输出完整 Markdown 内容
|
||
|
||
```bash
|
||
# 使用最佳可用解析器 (DOCX/PPTX/XLSX)
|
||
uv run parser.py report.docx
|
||
|
||
# 使用最佳可用解析器 (PDF)
|
||
uv run parser.py report.pdf
|
||
|
||
# 输出到文件
|
||
uv run parser.py report.docx > output.md
|
||
|
||
# 使用特定依赖
|
||
uv run --with python-docx parser.py report.docx > output.md
|
||
uv run --with pypdf parser.py report.pdf > output.md
|
||
```
|
||
|
||
### 2. 统计文档信息
|
||
|
||
```bash
|
||
# 统计字数
|
||
uv run --with markitdown parser.py report.docx -c
|
||
uv run --with unstructured parser.py report.pdf -c
|
||
|
||
# 统计行数
|
||
uv run --with markitdown parser.py report.docx -l
|
||
uv run --with pypdf parser.py report.pdf -l
|
||
```
|
||
|
||
### 3. 提取标题
|
||
|
||
```bash
|
||
# 提取所有标题
|
||
uv run --with python-docx parser.py report.docx -t
|
||
uv run --with unstructured parser.py report.pdf -t
|
||
|
||
# 输出示例(DOCX):
|
||
# 第一章 概述
|
||
## 1.1 背景
|
||
## 1.2 目标
|
||
# 第二章 实现
|
||
|
||
# 输出示例(PDF - 注意:PDF 通常不包含明确的标题层级):
|
||
[内容提取成功,但 PDF 可能缺乏清晰的标题结构]
|
||
```
|
||
|
||
### 4. 提取特定标题内容
|
||
|
||
```bash
|
||
# 提取特定章节
|
||
uv run --with python-docx parser.py report.docx -tc "第一章"
|
||
uv run --with unstructured parser.py report.pdf -tc "第一章"
|
||
|
||
# 输出该标题及其所有子内容
|
||
```
|
||
|
||
### 5. 搜索文档内容
|
||
|
||
```bash
|
||
# 搜索关键词
|
||
uv run --with markitdown parser.py report.docx -s "测试"
|
||
uv run --with unstructured parser.py report.pdf -s "测试"
|
||
|
||
# 使用正则表达式
|
||
uv run --with markitdown parser.py report.docx -s "章节\s+\d+"
|
||
uv run --with pypdf parser.py report.pdf -s "章节\s+\d+"
|
||
|
||
# 带上下文搜索(前后各2行)
|
||
uv run --with markitdown parser.py report.docx -s "重要内容" -n 2
|
||
uv run --with "markitdown[pdf]" parser.py report.pdf -s "重要内容" -n 2
|
||
|
||
# 输出示例:
|
||
---
|
||
这是重要内容的前两行
|
||
**重要内容**
|
||
这是重要内容后两行
|
||
---
|
||
```
|
||
|
||
## 解析器对比
|
||
|
||
### DOCX 解析器
|
||
|
||
| 解析器 | 优点 | 缺点 | 适用场景 |
|
||
|---------|------|--------|---------|
|
||
| **MarkItDown** | • 格式规范<br>• 微软官方支持<br>• 兼容性好 | • 需要安装<br>• 输出较简洁 | • 需要标准格式输出<br>• 自动化文档处理 |
|
||
| **python-docx** | • 输出最详细<br>• 保留完整结构<br>• 支持复杂样式 | • 需要安装<br>• 可能包含多余空行 | • 需要精确控制输出<br>• 分析文档结构 |
|
||
| **XML 原生** | • 无需依赖<br>• 运行速度快<br>• 输出原始内容 | • 格式可能不统一<br>• 样式处理有限 | • 依赖不可用时<br>• 快速提取内容 |
|
||
|
||
### PPTX 解析器
|
||
|
||
| 解析器 | 优点 | 缺点 | 适用场景 |
|
||
|---------|------|--------|---------|
|
||
| **MarkItDown** | • 格式规范<br>• 自动添加 Slide 分隔<br>• 输出简洁 | • 需要安装<br>• 详细度较低 | • 快速预览幻灯片<br>• 提取主要内容 |
|
||
| **python-pptx** | • 输出最详细<br>• 保留完整结构<br>• 支持层级列表 | • 需要安装<br>• 依赖私有 API | • 需要完整内容<br>• 分析演示结构 |
|
||
| **XML 原生** | • 无需依赖<br>• 结构化输出<br>• 运行速度快 | • 格式可能不统一<br>• 幻灯片分组简单 | • 依赖不可用时<br>• 结构化提取 |
|
||
|
||
### XLSX 解析器
|
||
|
||
| 解析器 | 优点 | 缺点 | 适用场景 |
|
||
|---------|------|--------|---------|
|
||
| **MarkItDown** | • 格式规范<br>• 支持多工作表<br>• 输出简洁 | • 需要安装<br>• 详细度较低 | • 快速预览表格<br>• 提取主要内容 |
|
||
| **pandas** | • 功能强大<br>• 支持复杂表格<br>• 数据处理灵活 | • 需要安装<br>• 依赖较多 | • 数据分析<br>• 复杂表格处理 |
|
||
| **XML 原生** | • 无需依赖<br>• 运行速度快<br>• 支持所有单元格类型 | • 格式可能不统一<br>• 无数据处理能力 | • 依赖不可用时<br>• 快速提取内容 |
|
||
|
||
### PDF 解析器
|
||
|
||
| 解析器 | 优点 | 缺点 | 适用场景 |
|
||
|---------|------|--------|---------|
|
||
| **MarkItDown** | • 格式规范<br>• 微软官方支持<br>• 兼容性好 | • 需要安装 `markitdown[pdf]`<br>• 输出较简洁 | • 需要标准格式输出<br>• 自动化文档处理 |
|
||
| **unstructured** | • 功能强大<br>• 支持表格提取<br>• 文本组织性好 | • 需要安装<br>• 可能包含页码标记 | • 需要完整内容<br>• 分析文档结构 |
|
||
| **pypdf** | • 轻量级<br>• 速度快<br>• 安装简单 | • 需要安装<br>• 功能相对简单 | • 快速提取内容<br>• 简单文本提取 |
|
||
|
||
## 输出格式
|
||
|
||
### Markdown 输出结构
|
||
|
||
```markdown
|
||
# 标题 1 (一级)
|
||
|
||
正文段落
|
||
|
||
## 标题 2 (二级)
|
||
|
||
- 列表项 1
|
||
- 列表项 2
|
||
|
||
1. 有序列表项 1
|
||
2. 有序列表项 2
|
||
|
||
| 列1 | 列2 | 列3 |
|
||
|------|------|------|
|
||
| 数据1 | 数据2 | 数据3 |
|
||
|
||
**粗体文本** *斜体文本* <u>下划线文本</u>
|
||
```
|
||
|
||
### PPTX 特有格式
|
||
|
||
```markdown
|
||
## Slide 1
|
||
|
||
幻灯片 1 的内容
|
||
|
||
## Slide 2
|
||
|
||
表格内容
|
||
|
||
幻灯片 2 的内容
|
||
|
||
---
|
||
```
|
||
|
||
### XLSX 特有格式
|
||
|
||
```markdown
|
||
# Excel数据转换结果
|
||
|
||
来源: /path/to/file.xlsx
|
||
|
||
## Sheet1
|
||
|
||
| 列1 | 列2 | 列3 |
|
||
|------|------|------|
|
||
| 数据1 | 数据2 | 数据3 |
|
||
```
|
||
|
||
### PDF 特有格式
|
||
|
||
```markdown
|
||
[PDF 文件的纯文本内容,按段落提取]
|
||
|
||
中电信粤亿迅〔2023〕3号
|
||
|
||
关于印发关于印发关于印发关于印发《《《《广东亿迅科技有限公司员工
|
||
|
||
[注:PDF 通常不包含明确的标题层级结构,内容以文本流形式呈现]
|
||
```
|
||
|
||
### 标题格式
|
||
|
||
- 标题使用 Markdown 井号语法:`#` 到 `######`(1-6级)
|
||
- 标题名称不包含井号
|
||
- 段落通过空行分隔
|
||
|
||
### 表格格式
|
||
|
||
```markdown
|
||
| 列1 | 列2 | 列3 |
|
||
|------|------|------|
|
||
| 数据1 | 数据2 | 数据3 |
|
||
```
|
||
|
||
### 列表格式
|
||
|
||
- 无序列表:使用 `-` 前缀
|
||
- 有序列表:使用 `1.` 前缀
|
||
- 支持多层缩进(使用空格)
|
||
|
||
## 内容处理
|
||
|
||
### 自动处理
|
||
|
||
1. **图片移除**:自动删除 Markdown 图片语法
|
||
2. **空行规范化**:合并连续空行为单个空行
|
||
3. **样式标签过滤**:移除 HTML span 标签
|
||
4. **RGB 颜色过滤**:移除颜色代码行
|
||
|
||
### 过滤规则(filter_markdown_content)
|
||
|
||
- 保留:文本、表格、列表、基本格式
|
||
- 移除:
|
||
- HTML 注释 (`<!-- ... -->`)
|
||
- Markdown 图片 (``)
|
||
- HTML 图片标签 (`<img>`, `</img>`)
|
||
- 媒体链接 (`[text](file.ext)`)
|
||
- RGB 颜色代码 (`R:255 G:255 B:255`)
|
||
- 标准化:多余空格合并为单个空格
|
||
|
||
## 错误处理
|
||
|
||
### 文件验证
|
||
|
||
```bash
|
||
# 文件不存在
|
||
错误: 文件不存在: missing.docx
|
||
|
||
# 无效格式
|
||
错误: 不是有效的 DOCX、PPTX、XLSX 或 PDF 格式: invalid.txt
|
||
```
|
||
|
||
### 解析器回退
|
||
|
||
脚本按优先级尝试解析器,如果失败则自动尝试下一个:
|
||
|
||
```
|
||
所有解析方法均失败:
|
||
- MarkItDown: 库未安装
|
||
- python-docx: 解析失败: ...
|
||
- XML 原生解析: document.xml 不存在或无法访问
|
||
```
|
||
|
||
**PDF 回退示例**:
|
||
|
||
```
|
||
所有解析方法均失败:
|
||
- MarkItDown: MarkItDown 解析失败: ...
|
||
- unstructured: unstructured 库未安装
|
||
- pypdf: pypdf 库未安装
|
||
```
|
||
|
||
所有解析方法均失败:
|
||
|
||
- MarkItDown: 库未安装
|
||
- python-docx: 解析失败: ...
|
||
- XML 原生解析: document.xml 不存在或无法访问
|
||
|
||
```
|
||
|
||
### 搜索错误
|
||
|
||
```bash
|
||
# 无效正则
|
||
错误: 正则表达式无效或未找到匹配: '[invalid'
|
||
|
||
# 标题未找到
|
||
错误: 未找到标题 '不存在的标题'
|
||
```
|
||
|
||
## 高级用法
|
||
|
||
### 结合 uv 运行
|
||
|
||
```bash
|
||
# 自动安装依赖并运行
|
||
uv run --with markitdown --with python-docx parser.py report.docx
|
||
|
||
# 输出到文件
|
||
uv run --with python-docx parser.py report.docx > output.md
|
||
```
|
||
|
||
### 批量处理
|
||
|
||
```bash
|
||
# 使用 find 或 glob 批量处理
|
||
for file in *.docx; do
|
||
uv run --with markitdown parser.py "$file" > "${file%.docx}.md"
|
||
done
|
||
|
||
# Windows PowerShell
|
||
Get-ChildItem *.docx | ForEach-Object {
|
||
uv run --with markitdown parser.py $_.FullName > ($_.BaseName + ".md")
|
||
}
|
||
```
|
||
|
||
### 管道使用
|
||
|
||
```bash
|
||
# 进一步处理 Markdown 输出
|
||
uv run --with markitdown parser.py report.docx | grep "重要" > important.md
|
||
|
||
# 统计处理
|
||
uv run --with markitdown parser.py report.docx -l | awk '{print $1}'
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### Q: 为什么有些内容没有提取到?
|
||
|
||
A: 不同解析器的输出详细度不同:
|
||
|
||
- `python-docx` / `python-pptx` 输出最详细
|
||
- `MarkItDown` 输出较简洁
|
||
- `XML 原生` 输出原始内容
|
||
|
||
如需完整内容,尝试使用专用库解析器。
|
||
|
||
### Q: PDF 文件没有标题层级?
|
||
|
||
A: PDF 是一种版面描述格式,通常不包含语义化的标题层级结构。与 DOCX/PPTX 不同,PDF 中的标题只是视觉上的文本样式,解析器无法准确识别标题层级。建议:
|
||
|
||
- 使用搜索功能查找特定内容
|
||
- 使用 `-l` 统计行数了解文档长度
|
||
- 使用 `-c` 统计字数了解文档规模
|
||
|
||
### Q: 表格格式不正确?
|
||
|
||
A: 确保原始文档中的表格结构完整。XML 解析器可能无法处理复杂表格。
|
||
|
||
### Q: 中文显示乱码?
|
||
|
||
A: 脚本输出使用 UTF-8 编码。确保终端支持 UTF-8:
|
||
|
||
```bash
|
||
# Linux/Mac
|
||
export LANG=en_US.UTF-8
|
||
|
||
# Windows PowerShell
|
||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||
```
|
||
|
||
### Q: 如何只使用特定解析器?
|
||
|
||
A: 当前版本自动选择最佳可用解析器。可以通过注释代码中的解析器列表来限制,或安装/卸载特定依赖。
|
||
|
||
### Q: MarkItDown 提示 PDF 依赖未安装?
|
||
|
||
A: MarkItDown 的 PDF 支持是可选依赖,需要使用 `markitdown[pdf]` 而非 `markitdown`:
|
||
|
||
```bash
|
||
# 错误
|
||
uv run --with markitdown parser.py file.pdf
|
||
|
||
# 正确
|
||
uv run --with "markitdown[pdf]" parser.py file.pdf
|
||
|
||
# 或手动安装
|
||
pip install "markitdown[pdf]"
|
||
```
|
||
|
||
### Q: 大文件处理慢?
|
||
|
||
A: 大文件建议使用 XML 原生解析(最快),或在脚本外部处理。
|
||
|
||
## 性能参考
|
||
|
||
基于测试文件的参考数据:
|
||
|
||
### DOCX (test.docx)
|
||
|
||
| 解析器 | 字符数 | 行数 | 相对速度 |
|
||
|---------|--------|------|---------|
|
||
| MarkItDown | ~8,500 | ~123 | 快 |
|
||
| python-docx | ~8,500 | ~123 | 中 |
|
||
| XML 原生 | ~8,500 | ~123 | 快 |
|
||
|
||
### PPTX (test.pptx)
|
||
|
||
| 解析器 | 字符数 | 行数 | 相对速度 |
|
||
|---------|--------|------|---------|
|
||
| MarkItDown | ~2,500 | ~257 | 快 |
|
||
| python-pptx | ~2,500 | ~257 | 中 |
|
||
| XML 原生 | ~2,500 | ~257 | 快 |
|
||
|
||
### XLSX (test.xlsx)
|
||
|
||
| 解析器 | 字符数 | 行数 | 相对速度 |
|
||
|---------|--------|------|---------|
|
||
| MarkItDown | ~6,000 | ~109 | 快 |
|
||
| pandas | ~6,000 | ~109 | 中 |
|
||
| XML 原生 | ~6,000 | ~109 | 快 |
|
||
|
||
### PDF (test.pdf)
|
||
|
||
| 解析器 | 字符数 | 行数 | 相对速度 |
|
||
|---------|--------|------|---------|
|
||
| MarkItDown | ~8,200 | ~1,120 | 快 |
|
||
| unstructured | ~8,400 | ~600 | 中 |
|
||
| pypdf | ~8,400 | ~600 | 快 |
|
||
|
||
## 代码风格
|
||
|
||
脚本遵循以下代码风格:
|
||
|
||
- Python 3.6+ 兼容
|
||
- 遵循 PEP 8 规范
|
||
- 所有公共 API 函数添加类型提示
|
||
- 字符串优先内联使用,不提取为常量,除非被使用超过3次
|
||
- 其他被多次使用的对象根据具体情况可考虑被提取为常量(如正则表达式)
|
||
- 模块级和公共 API 函数保留文档字符串
|
||
- 内部辅助函数不添加文档字符串(函数名足够描述)
|
||
- 变量命名清晰,避免单字母变量名
|
||
|
||
## 许可证
|
||
|
||
脚本遵循 PEP 8 规范,Python 3.6+ 兼容。
|
||
|
||
## 更新日志
|
||
|
||
### 最新版本
|
||
|
||
- 将单体脚本拆分为模块化结构(common.py, docx.py, pptx.py, xlsx.py, parser.py)
|
||
- 添加 XLSX 文件支持
|
||
- 添加 PDF 文件支持(MarkItDown、unstructured、pypdf)
|
||
- 增强错误处理(文件存在性检查、无效格式检测)
|
||
- 完善文档和示例
|
||
- 使用 uv 进行依赖管理和运行
|
||
- 所有模块通过语法检查和功能测试
|