From 5b362686e246083c625fa1790c9db2a8edc2afd9 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Sun, 15 Feb 2026 23:17:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0docling=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- temp/scripts/README.md | 66 ++++++++++++++++++++++++++++--------- temp/scripts/common.py | 18 ++++++++++ temp/scripts/docx_parser.py | 12 ++++++- temp/scripts/parser.py | 4 +++ temp/scripts/pdf_parser.py | 7 +++- temp/scripts/pptx_parser.py | 12 ++++++- temp/scripts/xlsx_parser.py | 7 +++- 7 files changed, 106 insertions(+), 20 deletions(-) diff --git a/temp/scripts/README.md b/temp/scripts/README.md index e64f54a..c4828f5 100644 --- a/temp/scripts/README.md +++ b/temp/scripts/README.md @@ -6,17 +6,19 @@ 该解析器按优先级尝试多种解析方法,确保最大兼容性: -1. **pypandoc-binary** (DOCX 专用,内置 Pandoc) - 生成结构化 Markdown -2. **MarkItDown** (微软官方库) - 推荐使用,格式最规范 -3. **python-docx / python-pptx / pandas** (成熟的 Python 库) - 输出最详细 -4. **unstructured / pypdf** (成熟的 PDF 库) - PDF 专用 -5. **XML 原生解析** (备选方案) - 无需依赖 +1. **Docling** (docling.document_converter) - 通用解析方案,优先覆盖 DOCX/PPTX/XLSX/PDF 并内置 OCR 能力 +2. **pypandoc-binary** (DOCX 专用,内置 Pandoc) - 生成结构化 Markdown +3. **MarkItDown** (微软官方库) - 推荐使用,格式规范 +4. **python-docx / python-pptx / pandas** (成熟的 Python 库) - 输出最详细 +5. **unstructured / pypdf** (成熟的 PDF 库) - PDF 专用 +6. **XML 原生解析** (备选方案) - 无需依赖 ### 特性 - 支持 DOCX、PPTX、XLSX 和 PDF 格式 - 自动检测文件类型和有效性 - 保留文本格式(粗体、斜体、下划线) +- Docling 作为第一优先解析器,单一依赖即可覆盖全部格式并自动调用 OCR - 提取表格并转换为 Markdown 格式 - 提取列表并保留层级结构 - 多种输出模式(字数、行数、标题、搜索等) @@ -27,11 +29,11 @@ ``` scripts/ -├── common.py # 公共函数和常量 -├── docx.py # DOCX 文件解析 -├── pptx.py # PPTX 文件解析 -├── xlsx.py # XLSX 文件解析 -├── pdf.py # PDF 文件解析 +├── common.py # 公共函数和常量 +├── docx_parser.py # DOCX 文件解析 +├── pptx_parser.py # PPTX 文件解析 +├── xlsx_parser.py # XLSX 文件解析 +├── pdf_parser.py # PDF 文件解析 ├── parser.py # 命令行入口 └── README.md # 本文档 ``` @@ -45,6 +47,20 @@ scripts/ uv run parser.py file.docx ``` +### 使用 Docling(推荐) + +```bash +# 通用解析方案,覆盖 DOCX/PPTX/XLSX/PDF +uv run --with docling parser.py file.docx +uv run --with docling parser.py file.pptx +uv run --with docling parser.py file.xlsx +uv run --with docling parser.py file.pdf +``` + +- Docling 是当前的默认第一优先级解析器,单一依赖即可获得统一输出。 +- 首次运行会自动下载 OCR/视觉模型到 `uv` 缓存目录,需保持网络连通。 +- 如果只需要 Docling,可无需安装其他解析依赖,脚本会在 Docling 失败时再回退至其他方案。 + ### 使用 pypandoc-binary(DOCX) ```bash @@ -92,7 +108,7 @@ pip install pypdf ```bash # 安装所有解析库 -uv run --with pypandoc-binary --with markitdown --with python-docx --with python-pptx --with pandas --with tabulate --with unstructured --with pypdf parser.py file.pdf +uv run --with docling --with pypandoc-binary --with markitdown --with python-docx --with python-pptx --with pandas --with tabulate --with unstructured --with pypdf parser.py file.pdf ``` ## 命令行用法 @@ -126,6 +142,10 @@ uv run parser.py [options] ### 1. 输出完整 Markdown 内容 ```bash +# 推荐:Docling 自动解析 +uv run --with docling parser.py report.docx +uv run --with docling parser.py report.pdf + # 使用最佳可用解析器 (DOCX/PPTX/XLSX) uv run parser.py report.docx @@ -209,38 +229,49 @@ uv run --with "markitdown[pdf]" parser.py report.pdf -s "重要内容" -n 2 DOCX 文件会按以下优先级依次尝试解析: -1. pypandoc-binary -2. MarkItDown -3. python-docx -4. XML 原生 +1. Docling +2. pypandoc-binary +3. MarkItDown +4. python-docx +5. XML 原生 | 解析器 | 优点 | 缺点 | 适用场景 | |---------|------|--------|---------| -| **pypandoc-binary** | • 自带 Pandoc,可直接使用
• 输出 Markdown 结构整洁
• 错误信息清晰易排查 | • 仅适用于 DOCX
• 依赖包体积较大 | • 需要标准化 Markdown 输出
• 首选解析路径 | +| **Docling** | • 单一依赖覆盖所有 Office/PDF 格式
• 自动带 OCR,复杂文档召回率高
• 输出 Markdown 结构稳定 | • 首次运行需下载较大的模型
• 运行时内存占用相对更高 | • 需要“一键完成”解析
• 需要 OCR/多模态支持 | +| **pypandoc-binary** | • 自带 Pandoc,可直接使用
• 输出 Markdown 结构整洁
• 错误信息清晰易排查 | • 仅适用于 DOCX
• 依赖包体积较大 | • 需要标准化 Markdown 输出
• Docling 不可用时的首选 | | **MarkItDown** | • 格式规范
• 微软官方支持
• 兼容性好 | • 需要安装
• 输出较简洁 | • 需要标准格式输出
• 自动化文档处理 | | **python-docx** | • 输出最详细
• 保留完整结构
• 支持复杂样式 | • 需要安装
• 可能包含多余空行 | • 需要精确控制输出
• 分析文档结构 | | **XML 原生** | • 无需依赖
• 运行速度快
• 输出原始内容 | • 格式可能不统一
• 样式处理有限 | • 依赖不可用时
• 快速提取内容 | ### PPTX 解析器 +PPTX 文件会按以下优先级依次尝试解析:Docling → MarkItDown → python-pptx → XML 原生。 + | 解析器 | 优点 | 缺点 | 适用场景 | |---------|------|--------|---------| +| **Docling** | • 解析幻灯片文本、表格与图片 OCR
• 自动生成统一 Markdown,包含分页分隔符 | • 需要下载模型
• 细节控制少 | • 需要一次性转换全部幻灯片
• 有图片或扫描件的 PPTX | | **MarkItDown** | • 格式规范
• 自动添加 Slide 分隔
• 输出简洁 | • 需要安装
• 详细度较低 | • 快速预览幻灯片
• 提取主要内容 | | **python-pptx** | • 输出最详细
• 保留完整结构
• 支持层级列表 | • 需要安装
• 依赖私有 API | • 需要完整内容
• 分析演示结构 | | **XML 原生** | • 无需依赖
• 结构化输出
• 运行速度快 | • 格式可能不统一
• 幻灯片分组简单 | • 依赖不可用时
• 结构化提取 | ### XLSX 解析器 +XLSX 文件会按以下优先级依次尝试解析:Docling → MarkItDown → pandas → XML 原生。 + | 解析器 | 优点 | 缺点 | 适用场景 | |---------|------|--------|---------| +| **Docling** | • 单次遍历导出全部工作表为 Markdown
• 自动处理合并单元格/图像 OCR | • 需要下载模型
• 对极大体积表可能较慢 | • 快速完成全表转 Markdown
• 含扫描图片的表格 | | **MarkItDown** | • 格式规范
• 支持多工作表
• 输出简洁 | • 需要安装
• 详细度较低 | • 快速预览表格
• 提取主要内容 | | **pandas** | • 功能强大
• 支持复杂表格
• 数据处理灵活 | • 需要安装
• 依赖较多 | • 数据分析
• 复杂表格处理 | | **XML 原生** | • 无需依赖
• 运行速度快
• 支持所有单元格类型 | • 格式可能不统一
• 无数据处理能力 | • 依赖不可用时
• 快速提取内容 | ### PDF 解析器 +PDF 文件会按以下优先级依次尝试解析:Docling → MarkItDown → unstructured → pypdf。 + | 解析器 | 优点 | 缺点 | 适用场景 | |---------|------|--------|---------| +| **Docling** | • 内置 RapidOCR,可处理扫描版 PDF
• 输出结构化 Markdown,包含表格/图片占位 | • 模型下载体积大
• OCR 耗时较长 | • 需要 OCR、表格/图片识别
• 多语言 PDF | | **MarkItDown** | • 格式规范
• 微软官方支持
• 兼容性好 | • 需要安装 `markitdown[pdf]`
• 输出较简洁 | • 需要标准格式输出
• 自动化文档处理 | | **unstructured** | • 功能强大
• 支持表格提取
• 文本组织性好 | • 需要安装
• 可能包含页码标记 | • 需要完整内容
• 分析文档结构 | | **pypdf** | • 轻量级
• 速度快
• 安装简单 | • 需要安装
• 功能相对简单 | • 快速提取内容
• 简单文本提取 | @@ -500,6 +531,8 @@ A: 大文件建议使用 XML 原生解析(最快),或在脚本外部处理 基于测试文件的参考数据: +> Docling 作为统一入口时,整体性能受 OCR/模型下载影响:首次运行略慢,缓存后与 MarkItDown 同量级,但在 PDF 场景中由于 OCR 会稍慢一些。 + ### DOCX (test.docx) | 解析器 | 字符数 | 行数 | 相对速度 | @@ -553,6 +586,7 @@ A: 大文件建议使用 XML 原生解析(最快),或在脚本外部处理 ### 最新版本 +- 新增 Docling 解析路径,统一处理 DOCX/PPTX/XLSX/PDF,并自动具备 OCR 能力 - DOCX 解析新增 pypandoc-binary 方案并设置为最高优先级 - 将单体脚本拆分为模块化结构(common.py, docx.py, pptx.py, xlsx.py, parser.py) - 添加 XLSX 文件支持 diff --git a/temp/scripts/common.py b/temp/scripts/common.py index 10cf99f..3e0f845 100644 --- a/temp/scripts/common.py +++ b/temp/scripts/common.py @@ -27,6 +27,24 @@ def parse_with_markitdown( return None, f"MarkItDown 解析失败: {str(e)}" +def parse_with_docling(file_path: str) -> Tuple[Optional[str], Optional[str]]: + """使用 docling 库解析文件""" + try: + from docling.document_converter import DocumentConverter + except ImportError: + return None, "docling 库未安装" + + try: + converter = DocumentConverter() + result = converter.convert(file_path) + markdown_content = result.document.export_to_markdown() + if not markdown_content.strip(): + return None, "文档为空" + return markdown_content, None + except Exception as e: + return None, f"docling 解析失败: {str(e)}" + + def build_markdown_table(rows_data: List[List[str]]) -> str: """将二维列表转换为 Markdown 表格格式""" if not rows_data or not rows_data[0]: diff --git a/temp/scripts/docx_parser.py b/temp/scripts/docx_parser.py index 4c095cd..9fcac57 100644 --- a/temp/scripts/docx_parser.py +++ b/temp/scripts/docx_parser.py @@ -5,7 +5,17 @@ import xml.etree.ElementTree as ET import zipfile from typing import Any, List, Optional, Tuple -from common import build_markdown_table, parse_with_markitdown, safe_open_zip +from common import ( + build_markdown_table, + parse_with_docling, + parse_with_markitdown, + safe_open_zip, +) + + +def parse_docx_with_docling(file_path: str) -> Tuple[Optional[str], Optional[str]]: + """使用 docling 库解析 DOCX 文件""" + return parse_with_docling(file_path) def parse_docx_with_pypandoc(file_path: str) -> Tuple[Optional[str], Optional[str]]: diff --git a/temp/scripts/parser.py b/temp/scripts/parser.py index 9e6d1ea..48bed7f 100644 --- a/temp/scripts/parser.py +++ b/temp/scripts/parser.py @@ -64,6 +64,7 @@ def main() -> None: if file_type == "docx": parsers = [ + ("docling", docx_parser.parse_docx_with_docling), ("pypandoc-binary", docx_parser.parse_docx_with_pypandoc), ("MarkItDown", docx_parser.parse_docx_with_markitdown), ("python-docx", docx_parser.parse_docx_with_python_docx), @@ -71,18 +72,21 @@ def main() -> None: ] elif file_type == "pptx": parsers = [ + ("docling", pptx_parser.parse_pptx_with_docling), ("MarkItDown", pptx_parser.parse_pptx_with_markitdown), ("python-pptx", pptx_parser.parse_pptx_with_python_pptx), ("XML 原生解析", pptx_parser.parse_pptx_with_xml), ] elif file_type == "xlsx": parsers = [ + ("docling", xlsx_parser.parse_xlsx_with_docling), ("MarkItDown", xlsx_parser.parse_xlsx_with_markitdown), ("pandas", xlsx_parser.parse_xlsx_with_pandas), ("XML 原生解析", xlsx_parser.parse_xlsx_with_xml), ] else: parsers = [ + ("docling", pdf_parser.parse_pdf_with_docling), ("MarkItDown", pdf_parser.parse_pdf_with_markitdown), ("unstructured", pdf_parser.parse_pdf_with_unstructured), ("pypdf", pdf_parser.parse_pdf_with_pypdf), diff --git a/temp/scripts/pdf_parser.py b/temp/scripts/pdf_parser.py index 234f422..2ba276e 100644 --- a/temp/scripts/pdf_parser.py +++ b/temp/scripts/pdf_parser.py @@ -3,7 +3,12 @@ from typing import Optional, Tuple -from common import parse_with_markitdown +from common import parse_with_docling, parse_with_markitdown + + +def parse_pdf_with_docling(file_path: str) -> Tuple[Optional[str], Optional[str]]: + """使用 docling 库解析 PDF 文件""" + return parse_with_docling(file_path) def parse_pdf_with_markitdown(file_path: str) -> Tuple[Optional[str], Optional[str]]: diff --git a/temp/scripts/pptx_parser.py b/temp/scripts/pptx_parser.py index b03506e..ec41628 100644 --- a/temp/scripts/pptx_parser.py +++ b/temp/scripts/pptx_parser.py @@ -6,7 +6,17 @@ import xml.etree.ElementTree as ET import zipfile from typing import Any, List, Optional, Tuple -from common import build_markdown_table, flush_list_stack, parse_with_markitdown +from common import ( + build_markdown_table, + flush_list_stack, + parse_with_docling, + parse_with_markitdown, +) + + +def parse_pptx_with_docling(file_path: str) -> Tuple[Optional[str], Optional[str]]: + """使用 docling 库解析 PPTX 文件""" + return parse_with_docling(file_path) def parse_pptx_with_markitdown(file_path: str) -> Tuple[Optional[str], Optional[str]]: diff --git a/temp/scripts/xlsx_parser.py b/temp/scripts/xlsx_parser.py index 778fb72..f4a6adf 100644 --- a/temp/scripts/xlsx_parser.py +++ b/temp/scripts/xlsx_parser.py @@ -5,7 +5,12 @@ import xml.etree.ElementTree as ET import zipfile from typing import List, Optional, Tuple -from common import parse_with_markitdown +from common import parse_with_docling, parse_with_markitdown + + +def parse_xlsx_with_docling(file_path: str) -> Tuple[Optional[str], Optional[str]]: + """使用 docling 库解析 XLSX 文件""" + return parse_with_docling(file_path) def parse_xlsx_with_markitdown(file_path: str) -> Tuple[Optional[str], Optional[str]]: