基于深度学习模型的文档解析工具

9/29/2023 MinerUPDF-Extract-KitDeepDocMarkerDoclingMarkitDownZeroX-OCR

# 1. 前言

# 1.1 PDF文档解析的困难

PDF文件并非传统意义上的数据格式,而更像是一系列打印指令的集合。这些指令告诉PDF阅读器或打印机如何在屏幕或纸张上展示文字、图像和其他元素。与HTML或DOCX等结构化文档不同,PDF文件不直接包含元素的逻辑结构,这使得从PDF中提取信息变得尤为困难。主要挑战包括:

  1. 页面布局的复杂性:PDF文档的布局可以非常多样,包括单栏、双栏、多列等,这增加了提取内容的难度。
  2. 文本提取的不准确性:由于PDF文件中的文本可能以图像形式嵌入,传统的文本提取方法可能无法准确获取所有内容。
  3. 图像和表格的识别:图像和表格的准确识别与解析是PDF解析中的另一大难题,特别是当它们与文本内容交织在一起时。

# 1.2 PDF文档解析的方法

# 1.2.1 基于规则的方法

基于规则的方法通过预定义的规则来确定PDF文档中每个部分的样式和内容。这种方法简单直接,但通用性不强,因为PDF的类型和布局多种多样,难以用有限的规则覆盖所有情况。

# 1.2.2 基于深度学习模型的方法

基于深度学习模型的方法利用神经网络来识别和解析PDF文档中的内容。这种方法通常结合了目标检测和OCR技术,能够更准确地识别文档中的文本、图像和表格。

  • 优势:能够处理复杂的页面布局,保留文档的结构信息。
  • 局限性:对象检测和OCR阶段可能比较耗时,且对计算资源的要求较高。

# 1.2.3 基于多模态大模型的方法

基于多模态大模型的方法利用大型预训练模型直接从PDF文档中提取复杂结构或关键信息。这种方法结合了文本、图像等多种模态的信息,能够更全面地理解文档内容。

  • 优势:能够提取或总结关键信息,适用于需要深度理解和分析的场景。
  • 局限性:需要将PDF处理成图像,将其发送给多模态大模型进行处理,对计算资源的要求较高。

# 1.3 文档解析工具对比

综合来看,基于深度学习模型的方法 > 基于多模态大模型的方法 > 基于规则提取的方法

  • MinerU是目前综合来看解析效果最好的,它可以识别公式,并且其表格解析和布局检测也更好 。
  • DeepDoc、Docling、MarkitDown这些文档解析工具各有千秋,可以根据实际文档情况结合使用。
  • ZeroX-OCR这个基于多模态大模型的工具就不用去试了,效果也不咋地,不知道怎么刷的高Star。
工具 RAGFlow Docling PDF-Extract-Kit MinerU
特色 强大的布局、表格、图像、公式识别 高效的多格式转换,尤其适用于Markdown输出,但不支持图片提取 强大的布局和公式识别,适用于学术类PDF文档,具有较强鲁棒性 提供多种格式的输出、OCR支持、多平台支持,适用于各种类型的PDF文档
支持的文件格式 PDF、DOCX、图片、HTML PDF、DOCX、PPTX、图片、HTML PDF PDF
输出格式 JSON Markdown、JSON Markdown、JSON、HTML、LaTeX公式、中间格式 Markdown、JSON、HTML、LaTeX公式、中间格式
输出的文本顺序 输出顺序可能不总是理想(尤其复杂布局时) 输出顺序良好,基本没有遗漏。对于有明显样式的docx文档可以实现标题分层级输出 输出文本顺序良好,但布局识别后的文本提取效果一般 输出符合人类阅读顺序,适应单栏、多栏及复杂排版
局限性 复杂布局时文本遗漏,图片识别不准确 不支持提取图片、图注不完整,PDF层级提取不明显 布局识别后的文本提取效果不好 对双栏中文文本提取效果差,标题无层级,图注提取差
布局识别 支持布局识别,包括标题、文本、表格、图片等 支持 使用 LayoutLMv3 进行布局检测(图像、表格、标题、文本等) 支持布局识别,包括标题、段落、列表、表格、图像等
公式识别 使用 YOLOv8 和 UniMERNet 进行公式检测和识别 自动识别并转换公式为LaTeX格式
OCR 支持 支持多种语言和字体,处理复杂文档布局和图像质量 支持 使用 PaddleOCR 进行文本识别 支持OCR(84种语言),检测和识别扫描版PDF与乱码PDF
表格提取 提取为HTML格式 提取为Markdown格式 准确提取表格内容 自动将表格提取为图片
图片提取 支持提取配图,但图像识别准确性较差且存在遗漏 不支持提取图片,仅提取图注 支持图像提取,并对图像进行区域检测 支持图像提取和图片描述,图注位于图片下方提取效果较好
页面元素 支持页头、页尾、参考引用、公式等 不支持提取页头、页尾等 支持页面元素的布局和公式识别 删除页眉、页脚、页码等元素,确保语义连贯
支持平台 Linux、MacOS、Windows Linux、MacOS、Windows Linux、MacOS、Windows 支持Windows、Linux、Mac平台
扩展性 可以与PaddleOCR等结合使用 支持OCR、图片描述等多种功能,可以扩展

# 2. MinerU文档解析

MinerU 是一个基于 PDF-Extract-Kit 构建的文档解析库,主要在工程层面进行了整合,大量复用了 PDF-Extract-Kit 的代码作为核心功能实现。

# 2.1 PDF-Extract-Kit内容提取

# 2.1.1 PDF-Extract-Kit简介

PDF-Extract-Kit 项目结合多样性PDF文档标注,训练了鲁棒的布局检测和公式检测模型。在论文、教材、研报、财报等多样性的PDF文档上,都能得到准确的提取结果,对于扫描模糊、水印等情况也有较高鲁棒性。

项目将PDF内容提取工作拆解为以下任务:

PDF-Extract-Kit

# 2.1.2 PDF-Extract-Kit输出格式

PDF-Extract-Kit 输出格式

{
    "layout_dets": [    # 页面上的元素
        {
            "category_id": 0, # 类别ID, 范围0~9, 13~15
            "poly": [
                136.0, # 坐标采用图像格式,需要转换回PDF坐标,顺序为左上、右上、右下、左下的x,y坐标
                781.0,
                340.0,
                781.0,
                340.0,
                806.0,
                136.0,
                806.0
            ],
            "score": 0.69,   # 置信度分数
            "latex": ''      # 公式识别结果,仅类别13, 14有内容,其他为空,类别15为OCR结果,此键将被替换为文本
        },
        ...
    ],
    "page_info": {         # 页面信息:提取边框时的分辨率大小,如果涉及缩放,可基于此信息进行对齐
        "page_no": 0,      # 页面编号
        "height": 1684,    # 页面高度
        "width": 1200      # 页面宽度
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

包含的类型 category_id 如下:

{
 0: 'title',              # 标题
 1: 'plain text',         # 纯文本
 2: 'abandon',            # 包括页眉、页脚、页码和页面注释
 3: 'figure',             # 图像
 4: 'figure_caption',     # 图像标题
 5: 'table',              # 表格
 6: 'table_caption',      # 表格标题
 7: 'table_footnote',     # 表格脚注
 8: 'isolate_formula',    # 显示公式(这是一种布局显示公式,优先级低于149: 'formula_caption',    # 显示公式标签

 13: 'inline_formula',    # 行内公式
 14: 'isolated_formula',  # 显示公式
 15: 'ocr_text'           # OCR结果
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2.1.3 PDF-Extract-Kit提取效果

项目训练了鲁棒的布局检测和公式检测模型,在论文、教材、研报、财报等PDF文档上,都能得到准确的提取结果。对于扫描模糊、水印等情况也有较高鲁棒性。

PDF-Extract-Kit提取效果

# 2.2 PDF-Extract-Kit使用实例

实验环境:Macbook Pro 2021,M1 Pro芯片,16G内存,macOS Sonoma 14.5系统,Python3.10环境

注:本项目适用于 Linux、MacOS、Windows 系统,其中 Linux 的安装教程即为官方主 README 里的,而 MacOS、Windows 里有单独的教程。

# 2.2.1 拉取代码并安装依赖

Step1:准备Conda环境

$ conda create -n pdf_extract_kit_env python=3.10    
$ conda activate pdf_extract_kit_env  
1
2

Step2:拉取代码安装依赖

$ git clone https://github.com/opendatalab/PDF-Extract-Kit.git
$ cd PDF-Extract-Kit
$ pip3 install unimernet==0.1.0
$ pip3 install -r requirements+cpu.txt

// 坑1:安装detectron2
$ pip3 install https://github.com/opendatalab/PDF-Extract-Kit/raw/main/assets/whl/detectron2-0.6-cp310-cp310-macosx_11_0_arm64.whl

// 坑2:安装freetype与imagemagick
$ brew install freetype imagemagick
$ open ~/.zshrc
export DYLD_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_LIBRARY_PATH"
$ source ~/.zshrc
$ echo $DYLD_LIBRARY_PATH
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意事项:

# 2.2.2 下载模型并修改配置

Step1:下载模型文件

$ pip3 install modelscope
1

download_models.py

# -*- coding: utf-8 -*-

import os
import shutil
from modelscope import snapshot_download

# 模型仓库的标识
model_id = "wanderkid/PDF-Extract-Kit"

# 下载模型到临时目录
temp_dir = "./temp_models"
model_dir = snapshot_download(model_id=model_id, cache_dir=temp_dir)

# 目标目录
target_dir = "./models"

# 确保目标目录存在
if not os.path.exists(target_dir):
    os.makedirs(target_dir)

# 移动文件
source_path = os.path.join(temp_dir, 'wanderkid', 'PDF-Extract-Kit', 'models')
for item in os.listdir(source_path):
    s = os.path.join(source_path, item)
    d = os.path.join(target_dir, item)
    if os.path.isdir(s):
        shutil.move(s, d)
    else:
        shutil.copy(s, d)

# 清理临时目录
shutil.rmtree(temp_dir)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

模型文件的文件结构:

./
├── Layout
│   ├── config.json
│   └── model_final.pth
├── MFD
│   └── weights.pt
├── MFR
│   └── UniMERNet
│       ├── config.json
│       ├── preprocessor_config.json
│       ├── pytorch_model.bin
│       ├── README.md
│       ├── tokenizer_config.json
│       └── tokenizer.json
│── TabRec
│   └─StructEqTable
│       ├── config.json
│       ├── generation_config.json
│       ├── model.safetensors
│       ├── preprocessor_config.json
│       ├── special_tokens_map.json
│       ├── spiece.model
│       ├── tokenizer.json
│       └── tokenizer_config.json 
└── README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Step2:修改运行环境配置

[1] 使用MPS进行加速推理

PDF-Extract-Kit/configs/model_configs.yaml:2

device: mps
1

PDF-Extract-Kit/modules/layoutlmv3/layoutlmv3_base_inference.yaml:72

DEVICE: mps
1

[2] 使用CPU进行推理

PDF-Extract-Kit/configs/model_configs.yaml:2

device: cpu
1

PDF-Extract-Kit/modules/layoutlmv3/layoutlmv3_base_inference.yaml:72

DEVICE: cpu
1

# 2.2.3 运行程序提取文档内容

$ python3 pdf_extract.py --vis --pdf ./assets/examples/example.pdf
1

参数含义:

  • --pdf:需要处理的PDF文件;如果传入的是文件夹,则会处理该文件夹中的所有PDF文件。
  • --output:结果保存路径,默认为“output”。
  • --vis:是否可视化结果;如果是,包括边界框和类别的检测结果将被可视化。
  • --render:是否渲染识别结果,包括公式的LaTeX代码和纯文本,这些将被渲染并放置在检测框中。注意:这个过程非常耗时,并且还需要先安装xelatex和imagemagic。

官方说在一些较新的 M 芯片设备上,MPS 加速无法激活,实测我这个 M1 Pro 芯片也无法使用 MPS 加速推理。

PDF-Extract-Kit无法MPS推理加速

因为我最终是使用CPU去运行的,所以推理速度很慢,使用官方测试文件耗时786s才处理完。

PDF-Extract-Kit使用CPU的推理速度

输出会给出一个json和一个pdf,实测的提取效果如下:

PDF-Extract-Kit提取效果

局限性:布局识别后的文本提取效果不好。

# 2.3 MinerU简介及使用实例

# 2.3.1 MinerU简介

MinerU 不仅能将混合了图片、公式、表格、脚注等在内的复杂多模态 PDF 文档精准转化为清晰、易于分析的 Markdown 格式;同时支持从包含广告等各种干扰信息或者复杂格式的网页、电子书中快速解析、抽取正式内容。有效提高AI语料准备效率,助力各行业利用大模型、RAG等技术,结合学术文献、财务报告、法律文件、电子书籍等专业文档,打造垂直领域的新知识引擎。

MinerU特点

# 2.3.2 MinerU使用实例

实验环境:实体GPU服务器,NVIDIA RTX 4090 / 24GB,CentOS 7.9,Anaconda3-2019.03,CUDA 12.4

原先实验PDF-Extract-Kit时已经将模型文件下载过了,这里就不必重复下载了,复用即可。

Step1:安装MinerU依赖环境

$ conda create -n MinerU python=3.10
$ conda activate MinerU
$ pip3 install magic-pdf[full]==0.7.0b1 --extra-index-url https://wheels.myhloli.com
1
2
3

Step2:创建配置文件

在用户目录(Linux可使用echo $HOME命令查看)创建配置文件magic-pdf.json,配置模板可从 magic-pdf.template.json (opens new window) 来获取。

{
    "models-dir":"/your_model_path/models",
    "device-mode":"cuda",
    "table-config": {
        "is_table_recog_enable": false,
        "max_time": 400
    }
}
1
2
3
4
5
6
7
8

Step3:使用MinerU解析文档

magic-pdf --help
Usage: magic-pdf [OPTIONS]

Options:
  -v, --version                display the version and exit
  -p, --path PATH              local pdf filepath or directory  [required]
  -o, --output-dir TEXT        output local directory
  -m, --method [ocr|txt|auto]  the method for parsing pdf.  
                               ocr: using ocr technique to extract information from pdf,
                               txt: suitable for the text-based pdf only and outperform ocr,
                               auto: automatically choose the best method for parsing pdf
                                  from ocr and txt.
                               without method specified, auto will be used by default. 
  --help                       Show this message and exit.


## show version
magic-pdf -v

## command line example
magic-pdf -p {some_pdf} -o {some_output_dir} -m auto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

以yolov9论文为例,输出结果包含以下内容:

.
├── images
├── layout.pdf
├── middle.json
├── model.json
├── origin.pdf
├── spans.pdf
└── yolov9.md
1
2
3
4
5
6
7
8

布局划分的效果如下,可以看到将需要提取的模块已经准确识别了。

MinerU解析效果

公式提取效果如下,可以看到已经将公式解析成LaTeX了。

MinerU公式提取效果

局限性:1)提取的md文件中标题没有层级。2)对于双栏中文文本提取效果较差,布局能够正确识别,但是输出为文本后混乱。3)对于图注在图片上方的图片提取效果较差。

# 2.3.3 MinerU踩坑记录

[1] 最初我是在 M1 的 macOS 上运行时,报错“illegal hardware instruction”,不知道是不是有兼容问题,又将其挪到了Linux上去运行。

[2] 在Linux上运行时又出现 /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found 报错。

Step1:首先使用如下命令进行查询,发现我的确没有3.4.20版本。
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX

Step2:然后我使用find命令进行查询,发现服务器上有满足要求的库
$ find / -name "libstdc++.so*" 

Step3:备份原来的库文件,再设置软链接(根据上一步的查询结果来设置),这时进行查询就有3.4.20版本了。
$ sudo mv /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so.6.bak
$ sudo ln -s /root/anaconda3/lib/libstdc++.so.6.0.25 /usr/lib64/libstdc++.so.6
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
注:如果实验完了需要还原,可以执行如下命令:
$ sudo mv /usr/lib64/libstdc++.so.6.bak /usr/lib64/libstdc++.so.6
1
2
3
4
5
6
7
8
9
10
11
12

# 2.4 MinerU的容器化API服务

实验环境:Debian12,512GB内存,256TB存储,Docker version 20.10.24、NVIDIA RTX 4090 / 24GB、CUDA 12.6

# 2.4.1 搭建MinerU的API服务

使用 nvidia-smi 命令查一下显卡的占用情况,找一个显存充足的显卡用于部署(我在实际部署时占用了6200MB的显存),换掉 --gpus device=2 参数即可。

$ docker pull registry.cn-beijing.aliyuncs.com/quincyqiang/mineru:0.2-models
$ docker run -itd --name=mineru_server --gpus device=2 -p 8000:8000 registry.cn-beijing.aliyuncs.com/quincyqiang/mineru:0.2-models
1
2

注:作者的这个镜像里使用的依赖环境是GPU版的,CPU下无法直接运行,如果要用的话要自己去换依赖,使用CPU的推理速度很慢,没啥实际使用的价值,没GPU建议不要用了。

# 2.4.2 使用MinerU的API服务

使用 Chrome 访问 http://ip:8000/docs 地址即可查看接口文档,支持的参数如下:

  • pdf_file: 需要解析的PDF文件。
  • parse_method: 解析方法,支持 "auto"、"ocr" 或 "txt" 三种方式。默认是 "auto"。如果解析结果不满意,可以尝试使用 "ocr" 方法。
  • model_json_path: 已有模型数据文件的路径。如果为空,将使用内置模型。PDF文件和模型文件必须对应。
  • is_json_md_dump: 是否将解析的数据写入 .json 和 .md 文件。默认为True。数据的不同阶段将分别保存到3个不同的 .json 文件中,md内容将保存到 .md 文件中。
  • output_dir: 结果输出目录。将在该目录下创建一个以PDF文件命名的文件夹,用于存储所有结果。

这里我将 is_json_md_dump 参数设置成 false,然后上传了一篇 yolov9的论文进行测试。

MinerU的API接口文档

这篇论文有18页,在该GPU环境下耗时28s获取到了结果,提取的速度和效果看起来还行。

MinerU的API服务

注:涉及图片的部分,返回值里是相对引用,存放在容器内 /tmp/文件名/images 目录下。

# 2.5 MinerU解析流程拆解

# 2.5.1 解析流程拆解

这里以 v1.3.10 版本为例,深入拆解下它进行文档解析时的内部操作细节。

MinerU解析流程拆解

下面根据官方提供的运行示例,一步步拆解具体的流程。

import os

# 导入必要的模块和类
from magic_pdf.data.data_reader_writer import FileBasedDataWriter, FileBasedDataReader
from magic_pdf.data.dataset import PymuDocDataset
from magic_pdf.model.doc_analyze_by_custom_model import doc_analyze
from magic_pdf.config.enums import SupportedPdfParseMethod

# 参数设置
pdf_file_name = "file.pdf" # 要处理的PDF文件路径,使用时替换为实际路径
name_without_suff = pdf_file_name.split(".")[0]  # 去除文件扩展名

# 准备环境
local_image_dir, local_md_dir = "output/images", "output" # 图片和输出目录
image_dir = str(os.path.basename(local_image_dir))  # 获取图片目录名

# 创建输出目录(如果不存在)
os.makedirs(local_image_dir, exist_ok=True)

# 初始化数据写入器
image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(
    local_md_dir
)

# 读取PDF文件内容
reader1 = FileBasedDataReader("")  # 初始化数据读取器
pdf_bytes = reader1.read(pdf_file_name)  # 读取PDF文件内容为字节流

# 处理流程
## 创建PDF数据集实例
ds = PymuDocDataset(pdf_bytes)  # 使用PDF字节流初始化数据集

## 推理阶段
if ds.classify() == SupportedPdfParseMethod.OCR:
    # 如果是OCR类型的PDF(扫描件/图片型PDF)
    infer_result = ds.apply(doc_analyze, ocr=True)  # 应用OCR模式的分析

    ## 处理管道
    pipe_result = infer_result.pipe_ocr_mode(image_writer)  # OCR模式的处理管道

else:
    # 如果是文本型PDF
    infer_result = ds.apply(doc_analyze, ocr=False)  # 应用普通文本模式的分析

    ## 处理管道
    pipe_result = infer_result.pipe_txt_mode(image_writer)  # 文本模式的处理管道

### 绘制模型分析结果到每页PDF
infer_result.draw_model(os.path.join(local_md_dir, f"{name_without_suff}_model.pdf"))

### 获取模型推理结果
model_inference_result = infer_result.get_infer_res()

### 绘制布局分析结果到每页PDF
pipe_result.draw_layout(os.path.join(local_md_dir, f"{name_without_suff}_layout.pdf"))

### 绘制文本块(span)分析结果到每页PDF
pipe_result.draw_span(os.path.join(local_md_dir, f"{name_without_suff}_spans.pdf"))

### 获取Markdown格式的内容
md_content = pipe_result.get_markdown(image_dir)  # 包含图片相对路径

### 保存Markdown文件
pipe_result.dump_md(md_writer, f"{name_without_suff}.md", image_dir)

### 获取内容列表(JSON格式)
content_list_content = pipe_result.get_content_list(image_dir)

### 保存内容列表到JSON文件
pipe_result.dump_content_list(md_writer, f"{name_without_suff}_content_list.json", image_dir)

### 获取中间JSON格式数据
middle_json_content = pipe_result.get_middle_json()

### 保存中间JSON数据
pipe_result.dump_middle_json(md_writer, f'{name_without_suff}_middle.json')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

[1] 数据读取

调用:magic_pdf\data\data_reader_writer\filebase.pyFileBasedDataReaderread_at方法

def read_at(self, path: str, offset: int = 0, limit: int = -1) -> bytes:
    """Read at offset and limit.

    Args:
        path (str): the path of file, if the path is relative path, it will be joined with parent_dir.
        offset (int, optional): the number of bytes skipped. Defaults to 0.
        limit (int, optional): the length of bytes want to read. Defaults to -1.

    Returns:
        bytes: the content of file
    """
    fn_path = path
    if not os.path.isabs(fn_path) and len(self._parent_dir) > 0:
        fn_path = os.path.join(self._parent_dir, path)

    with open(fn_path, 'rb') as f:
        f.seek(offset)
        if limit == -1:
            return f.read()
        else:
            return f.read(limit)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

可设定offsetlimit两个参数:

  • offset:控制读取时的偏移量,比如从第n个字符后开始读取
  • limit:控制读取的长度,比如读取n个字符

默认读取文件所有内容,以二进制形式读取,直接加载进内存。如果文件特别大,可以考虑用这两个参数做分批读取。

[2] 文件类型分类

对于PDF文件,进一步判断是图片型PDF(扫描件)还是文本型PDF。具体判断逻辑在magic_pdf\filter\pdf_classify_by_type.pyclassify函数:

def classify(total_page: int, page_width, page_height, img_sz_list: list, text_len_list: list, img_num_list: list,invalid_chars: bool):
    results = {
        'by_image_area': classify_by_area(total_page, page_width, page_height, img_sz_list, text_len_list),
        'by_text_len': classify_by_text_len(text_len_list, total_page),
        'by_avg_words': classify_by_avg_words(text_len_list),
        'by_img_num': classify_by_img_num(img_sz_list, img_num_list),
        # 'by_text_layout': classify_by_text_layout(text_layout_list),
        'by_img_narrow_strips': classify_by_img_narrow_strips(page_width, page_height, img_sz_list),
        'by_invalid_chars': invalid_chars,
    }
1
2
3
4
5
6
7
8
9
10

这里进行了多方面的判断,具体方式如下:

  • classify_by_area 如果 PDF 里大部分页面(超过一半)的主要内容都是一张大图片(图片面积占了页面面积的一半以上),那就认为这个 PDF 是扫描件,需要 OCR 处理,否则认为这个 PDF 是文本型的(返回 True)。在判断前,它会先尝试去掉水印图片,并把可能被切成小块的图片拼起来。
  • classify_by_text_len 随机抽取一部分页面,只要其中任何一页的文字数量超过 100 个字符,就认为这个 PDF 是文本型的(返回 True)。
  • classify_by_avg_words 计算 PDF 所有页面的平均字符数,如果平均每页字符数超过 100,就认为这个 PDF 是文本型的(返回 True)。
  • classify_by_img_num 检查 PDF 是否属于一种特殊扫描件,其特点是:去除重复图片后,几乎每页都没有有效图片了,但原始图片数量在大部分页面上都非常多且数量一致。如果不是这种情况,就认为它是文本型 PDF(返回 True)。
  • classify_by_img_narrow_strips 检查 PDF 是否有一半以上的页面,其绝大部分图片(至少 5 张且占该页图片总数的 80% 以上)都是非常细长的(即宽度占页面宽度的 90% 以上且至少是高度的 4 倍,或者高度占页面高度的 90% 以上且至少是宽度的 4 倍)。如果这种情况的页面比例低于 50%,则认为 PDF 在这个维度上倾向于是文本型的(返回 True)。
  • invalid_chars 在扫描 PDF 文件内容时,是否检测到了无效或无法正常显示的字符,如果没有,判定为文本型(返回 True)。

最后,综合这6个条件,如果这6个条件都为True,即判定文件是文本型的PDF,有任意条件不通过,则判定文件为图片型PDF。

[3] 设备选择

在正式处理前,需要先指定运行设备。首先需要读取配置文件,相关代码在MinerU\magic_pdf\libs\config_reader.py

# 定义配置文件名常量
CONFIG_FILE_NAME = os.getenv('MINERU_TOOLS_CONFIG_JSON', 'magic-pdf.json')

def read_config():
    if os.path.isabs(CONFIG_FILE_NAME):
        config_file = CONFIG_FILE_NAME
    else:
        home_dir = os.path.expanduser('~')
        config_file = os.path.join(home_dir, CONFIG_FILE_NAME)

    ifnot os.path.exists(config_file):
        raise FileNotFoundError(f'{config_file} not found')

    with open(config_file, 'r', encoding='utf-8') as f:
        config = json.load(f)
    return config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

代码表明,它会根据系统环境变量MINERU_TOOLS_CONFIG_JSON去查找json的配置文件。如果未设置此环境变量,默认会到用户home目录下,寻找magic-pdf.json这个文件。

该文件中,device-mode设定了模型运行的设备,有cpucudanpu三种模式进行选择(如果填入值非这三类,视作cpu)。如果选择了cudanpu,会自动计算显存容量,并自适应调节batch_ratio,具体调节规则如下:

if gpu_memory >= 16:
    batch_ratio = 16
elif gpu_memory >= 12:
    batch_ratio = 8
elif gpu_memory >= 8:
    batch_ratio = 4
elif gpu_memory >= 6:
    batch_ratio = 2
else:
    batch_ratio = 1
1
2
3
4
5
6
7
8
9
10

对于CPU设备,batch_ratio默认设为1。除此之外,在配置文件中,无法显性指定多卡同时解析,如有多卡解析的需求,可参考基于 LitServe 的多 GPU 并行处理方案,详见:https://github.com/opendatalab/MinerU/tree/master/projects/multi_gpu (opens new window)

[4] 解析处理

具体的处理流程在magic_pdf\model\batch_analyze.py。图片型PDF会比文本型PDF多一个OCR处理的步骤,其它步骤一致。

1)布局分析

布局分析提供了两套模型可供选择:layoutlmv3doclayout_yolo,默认用后者,DocLayout-YOLO (opens new window) 也是OpenDataLab的。该算法是基于YOLO-v10对文件布局标记的数据集D4LADocSynth300K进行训练,从而检测出不同的布局信息。

DocLayout-YOLO布局识别

2)公式处理

公式处理包含两个阶段:公式检测(MFD)和 公式识别(MFR)。

  • 公式检测是指检测出公式所在位置,采用yolo_v8_mfd算法,未找到该算法的详细介绍,根据揣测是采用yolov8算法,在公式块标记的相关数据集上进行训练得到。
  • 公式识别是指在得到公式区域的基础上,识别其中的具体内容,将其中的数学表达式图像转换为 LaTeX ,具体算法采用 UniMERNet (opens new window)算法,该算法也是OpenDataLab的自研算法。

考虑到并不是所有的PDF文件中都有公式,因此,可以在配置文件中,将其关闭。默认的"enable"设置为开启状态,如需关闭公式处理,设为false

"formula-config": {
    "mfd_model": "yolo_v8_mfd",
    "mfr_model": "unimernet_small",
    "enable": true
},
1
2
3
4
5

3)OCR处理

OCR是指将图像区域内容识别成文本,和公式处理类似,同样包含区域检测和区域识别两个阶段。这两个阶段均是使用PaddleOCR,该算法原生使用的PaddlePaddle框架,这里使用了Pytorch的实现版本。

magic_pdf\model\sub_modules\ocr\paddleocr2pytorch\pytorch_paddle.py中,有一个测试样例。对于不同的语言进行OCR,使用不同的模型,在magic_pdf\model\sub_modules\ocr\paddleocr2pytorch\pytorchocr\utils\resources\models_config.yml这个配置文件,规定了不同语言所对应的采取的不同模型。

对于中文,检测模型使用ch_PP-OCRv3_det_infer,识别模型采用ch_PP-OCRv4_rec_infer。在下载模型时,会将所有常见语言(中文、英文、日文、拉丁文等语言)的模型一次性下载下来,每个模型体积不大,基本在10-20MB左右。

4)表格识别

表格识别包含两个部分:表格文本识别和表格结构识别,该部分代码来自 RapidTable (opens new window) 仓库。

  • 表格文本识别默认采用rapid_table这个依赖库,底层同样使用的是PaddleOCR,用来识别表格中的文本内容。
  • 表格结构识别默认采用slanet_plus算法,用来识别表格结构。

表格识别同样可以在配置文件中自由选择关闭,和公式处理一样,通过enable参数来控制开启和关闭。

    "table-config": {
        "model": "rapid_table",
        "sub_model": "slanet_plus",
        "enable": true,
        "max_time": 400
    },
1
2
3
4
5
6

5)结果输出

最后可输出结果包括:

  • model.pdf:布局分析的可视化结果
  • file_layout.pdf:布局分析后,去除页眉页脚,标记真正内容的可视化结果
  • spans.pdf:文本/图像/公式/表格区域检测的可视化结果
  • middle.json:每一区域识别的中间结果
  • content_list.json:分块内容识别结果,对每段落的小块区域进行合并

具体的相关接口参见magic_pdf\operators\pipes.py

# 2.5.2 其它文件处理

由于MinerU是针对PDF进行解析,因此本身的处理管道并不能处理其它格式的文件。

v1.0.1版本后,进一步支持图像(.jpg及.png)、Word(.doc及.docx)、以及PPT(.ppt及.pptx)三类文件的解析。

[1] MS-Office文件解析

对于 MS-Office 文件,需要通过 LibreOffice 将其转换成 PDF文件,再复用PDF的解析管道。(本地使用时,需要提前安装LibreOffice,并设置相应环境变量)

import os

from magic_pdf.data.data_reader_writer import FileBasedDataWriter, FileBasedDataReader
from magic_pdf.model.doc_analyze_by_custom_model import doc_analyze
from magic_pdf.data.read_api import read_local_office

# prepare env
local_image_dir, local_md_dir = "output/images", "output"
image_dir = str(os.path.basename(local_image_dir))

os.makedirs(local_image_dir, exist_ok=True)

image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(
    local_md_dir
)

# proc
## Create Dataset Instance
input_file = "demo.pptx"     # replace with real ms-office file

input_file_name = input_file.split(".")[0]
ds = read_local_office(input_file)[0]


infer_result = ds.apply(doc_analyze, ocr=True)

## 处理管道
pipe_result = infer_result.pipe_ocr_mode(image_writer) 

pipe_result.dump_md(md_writer, f"{input_file_name}.md", image_dir)

### 获取内容列表(JSON格式)
content_list_content = pipe_result.get_content_list(image_dir)

### 保存内容列表到JSON文件
pipe_result.dump_content_list(md_writer, f"{input_file_name}_content_list.json", image_dir)

### 获取中间JSON格式数据
middle_json_content = pipe_result.get_middle_json()

### 保存中间JSON数据
pipe_result.dump_middle_json(md_writer, f'{input_file_name}_middle.json')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

具体转换过程在magic_pdf\data\read_api.py文件的read_local_office方法。

[2] 图片文件解析示例

对于图片文件,无需转换成pdf,原本的管道可兼容,示例python脚本如下:

import os

from magic_pdf.data.data_reader_writer import FileBasedDataWriter, FileBasedDataReader
from magic_pdf.model.doc_analyze_by_custom_model import doc_analyze
from magic_pdf.data.read_api import read_local_images

# prepare env
local_image_dir, local_md_dir = "output/images", "output"
image_dir = str(os.path.basename(local_image_dir))

os.makedirs(local_image_dir, exist_ok=True)

image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(
    local_md_dir
)

# proc
## Create Dataset Instance
input_file = "demo.jpg"   # replace with real image file
input_file_name = input_file.split(".")[0]

ds = read_local_images(input_file)[0]

infer_result = ds.apply(doc_analyze, ocr=True)

## 处理管道
pipe_result = infer_result.pipe_ocr_mode(image_writer) 

pipe_result.dump_md(md_writer, f"{input_file_name}.md", image_dir)

### 获取内容列表(JSON格式)
content_list_content = pipe_result.get_content_list(image_dir)

### 保存内容列表到JSON文件
pipe_result.dump_content_list(md_writer, f"{input_file_name}_content_list.json", image_dir)

### 获取中间JSON格式数据
middle_json_content = pipe_result.get_middle_json()

### 保存中间JSON数据
pipe_result.dump_middle_json(md_writer, f'{input_file_name}_middle.json')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 3. Marker文档解析

Marker是一个将PDF文档转换Markdown的库,OmniParse文档解析平台是基于Marker来实现的。

# 3.1 Marker将文档转换Markdown

# 3.1.1 Marker简介

Marker能将PDF、EPUB和MOBI转换为Markdown。它比nougat快10倍,对大多数文档的准确度更高,并且幻觉风险低。

  • 支持各种PDF文档(针对书籍和科学论文进行优化)
  • 移除页眉/页脚/其他杂项
  • 将大部分方程式转换为LaTeX
  • 格式化代码块和表格
  • 支持多种语言(尽管大部分测试都是用英语完成),查看settings.py以获取语言列表
  • 可在GPU、CPU或MPS上运行

项目地址:https://github.com/VikParuchuri/marker (opens new window)

marker与nougat对比

# 3.1.2 Marker使用实例

[1] 准备运行环境

实验环境:Macbook Pro 2021,M1 Pro芯片,16G内存,macOS Ventura13.2.1系统,Python3.9环境

$ git clone https://github.com/VikParuchuri/marker.git
$ pip3 install -r requirements.txt
$ pip3 install -r scripts/install/brew-requirements.txt
1
2
3

使用官方requirements安装完依赖后,我这里有各种报错,又安装了如下依赖才成功跑起来。

$ brew install tesseract-lang
$ brew install ghostscript 
$ brew install libmagic 

$ pip3 install ftfy
$ pip3 install pyspellchecker 
$ pip3 install ocrmypdf 
$ pip3 install thefuzz 
$ pip3 uninstall nougat
$ pip3 install nougat-ocr
$ pip3 install --upgrade transformers   
$ pip3 install python-magic
$ pip3 install ray

报错信息:ImportError: cannot import name 'NougatModel' from 'nougat' 
解决方案:不要安装 Nougat,只需安装 Nougat-OCR。pip3 uninstall nougat 及 pip3 install nougat-ocr

报错信息:ValueError: Non-consecutive added token '<pad>' found. Should have index 259 but has index 0 in saved vocabulary.
解决方案:更新transformers即可。pip3 install --upgrade transformers  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

[2] 解析PDF文档

这里以转换单个文件为例,首次执行时,会自动下载模型。官方支持对文档进行批处理,也有很多超参可以控制转换配置,详见官方README,这里就不赘述了。

$ python3 convert_single.py input/input.pdf output/output.md --parallel_factor 20
1

--parallel_factor 是批量大小和并行 OCR 工作人员增加多少。数字越大,需要的 VRAM 和 CPU 越多,但处理速度越快,默认设置为 1。

Marker解析PDF文档效果

注:这个工具只提取PDF文档里的文本,表格什么的也能解析,但对于图表,解析时会将其丢弃。

# 3.1.3 将Marker封装成Docker

实验环境:Debian 11 x86_64、Docker version 20.10.17、无GPU。

  • 将Marker封装成Docker,方便在其他服务器环境上迁移部署。
  • 实测安装依赖及模型需要占用大约12GB存储,运行时至少需要4GB内存,对资源的占用要求还是不小的。

requirements.txt

scikit-learn == 1.3.2
Pillow == 10.1.0
pytesseract == 0.3.10
PyMuPDF == 1.23.5
pymupdf-fonts == 1.0.5
pydantic == 2.4.2
pydantic-settings == 2.0.3
nougat-ocr == 0.1.17
transformers == 4.34.1
numpy == 1.26.1
python-dotenv == 1.0.0
torch == 2.1.1
ray == 2.7.1
tqdm == 4.66.1
tabulate == 0.9.0
thefuzz == 0.20.0
python-magic == 0.4.27
pyspellchecker == 0.7.2
ftfy == 6.1.1
nltk == 3.8.1
ocrmypdf == 15.4.0
bitsandbytes == 0.41.2.post2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Dockerfile

# 基于python3.9镜像创建新镜像
FROM python:3.9
# 创建容器内部目录
RUN mkdir /code
# 将项目复制到内部目录
ADD . /code/
# 切换到工作目录
WORKDIR /code
# 安装项目依赖
RUN pip install -r requirements.txt
# 安装vim命令
RUN apt-get update && apt-get install vim -y  
1
2
3
4
5
6
7
8
9
10
11
12

build.sh

#!/bin/bash

base_path=$(cd `dirname $0`; pwd)
input_path="${base_path}/input"
output_path="${base_path}/output"

docker build -t marker-image .                                  
docker run -itd --name marker -v ${input_path}:/code/input -v ${output_path}:/code/output marker-image:latest  
docker update marker --restart=always                           
1
2
3
4
5
6
7
8
9

新建 input 和 output 目录,执行 build.sh 脚本构建镜像与容器,之后在 input 目录上传用于测试的 PDF 文件,进入容器执行。

$ docker exec -it marker /bin/bash
$ python3 convert_single.py input/input.pdf output/output.md --parallel_factor 1
1
2

# 3.2 OmniParse文档解析平台

# 3.2.1 OmniParse简介

OmniParse 是一个能够将各种非结构化数据(如文档、图片、视频等)转换为结构化数据的开源平台。它支持20多种文件类型,所有的数据处理都在本地完成,不需要通过外部API,从而确保用户的数据隐私和安全。

OmniParse

# 3.2.2 OmniParse搭建

实验环境:实体GPU服务器,NVIDIA RTX 4090 / 24GB,CentOS 7.9,Anaconda3-2019.03,CUDA 12.4

$ docker pull savatar101/omniparse:0.1
$ docker run -itd --name omniparse --gpus all -p 8000:8000 -e HF_ENDPOINT=https://hf-mirror.com savatar101/omniparse:0.1 python server.py --host 0.0.0.0 --port 8000 --documents --media
$ docker logs -f omniparse
1
2
3

注意事项:因为国内网络环境的缘故,遇到了一些坑。

  • 因为要从Huggingface下载模型,而国内网络不能直连,因此设置了 -e HF_ENDPOINT=https://hf-mirror.com 镜像源,若是境外网络则不需要此配置。
  • 也有可能是国内网络的原因,我运行到 Loading Web Crawler 阶段就会报错,而 Web Crawler 我并不需要,因此在 docker run 时重写覆盖了Dockerfile里的CMD命令,将 --web 去掉了。

# 3.2.3 OmniParse使用

使用 Chrome 浏览器打开 http://ip:8000 地址,即可通过Web的方式使用 OmniParse 工具。

OmniParse主界面

OmniParse的提取效果如下:

OmniParse提取效果

其中提取出的图片是单独列出的:

OmniParse提取出的图片

除此之外,OmniParse还支持输出JSON格式的提取结果,并支持API调用。

OmniParse提取的JSON格式及API调用

# 4. DeepDoc文档解析

# 4.1 DeepDoc简介

DeepDoc是RAGFlow开源项目中提出的一个支持多种文本切片的解析模版,它利用视觉信息和解析技术,对文档进行深度理解,提取文本、表格和图像等信息。它的功能模块包括:

  • 布局识别:使用 Yolov8 进行布局识别/OCR/TSR,识别文档的布局结构,例如标题、段落、表格、图像等。
  • OCR识别:支持多种语言和字体,并能够处理复杂的文档布局和图像质量。
  • TSR识别:识别表格的结构,例如行列、表头、单元格合并等,并将其转换为自然语言句子。
  • 文档解析:支持解析 PDF、DOCX、EXCEL 和 PPT 等多种文档格式,并提取文本块、表格和图像等信息。
  • 简历解析:将简历中的非结构化文本解析为结构化数据,例如姓名、联系方式、工作经历、教育背景等。

官方详细介绍:https://github.com/infiniflow/ragflow/blob/main/deepdoc/README.md (opens new window)

# 4.2 DeepDoc使用实例

实验环境:Macbook Pro 2021,M1 pro芯片,16G内存,macOS Ventura13.2.1系统,Python3.9环境

# 4.2.1 OCR光学字符识别

OCR(Optical Character Recognition,光学字符识别)

由于许多文档都是以图像形式呈现的,或者至少能够转换为图像,因此OCR是文本提取的一个非常重要、基本,甚至通用的解决方案。

$ python3 deepdoc/vision/t_ocr.py -h
usage: t_ocr.py [-h] --inputs INPUTS [--output_dir OUTPUT_DIR]

options:
  -h, --help            show this help message and exit
  --inputs INPUTS       Directory where to store images or PDFs, or a file path to a single image or PDF
  --output_dir OUTPUT_DIR
                        Directory where to store the output images. Default: './ocr_outputs'
1
2
3
4
5
6
7
8

使用实例:输入可以是图像或PDF的目录,也可以是图像或PDF,输出是每一页的TXT与JPG。

$ python3 deepdoc/vision/t_ocr.py --inputs=./data/yolov9论文.pdf --output_dir=./output
1

DeepDoc的OCR光学字符识别

# 4.2.2 TSR表结构识别

TSR(Table Structure Recognition,表结构识别)

数据表是一种常用的结构,用于表示包括数字或文本在内的数据。表的结构可能非常复杂,比如层次结构标题、跨单元格和投影行标题。除了TSR,我们还将内容重新组合成LLM可以很好理解的句子。TSR任务有五个标签:列、行、列标题、行标题、合并单元格。

$ python3 deepdoc/vision/t_recognizer.py -h
usage: t_recognizer.py [-h] --inputs INPUTS [--output_dir OUTPUT_DIR] [--threshold THRESHOLD] [--mode {layout,tsr}]

options:
  -h, --help            show this help message and exit
  --inputs INPUTS       Directory where to store images or PDFs, or a file path to a single image or PDF
  --output_dir OUTPUT_DIR
                        Directory where to store the output images. Default: './layouts_outputs'
  --threshold THRESHOLD
                        A threshold to filter out detections. Default: 0.5
  --mode {layout,tsr}   Task mode: layout recognition or table structure recognition
1
2
3
4
5
6
7
8
9
10
11

使用实例:输入可以是图像或PDF的目录,也可以是图像或PDF,输出是每一页的HTML与JPG。

$ python3 deepdoc/vision/t_recognizer.py --inputs=./data/住宿标准.pdf --output_dir=./output --threshold=0.2 --mode=tsr
1

DeepDoc的TSR表结构识别

# 5. Docling文档解析

# 5.1 Docling简介

Docling是一个开源文档解析和转换工具,能高效地将多种格式的文档(PDF、DOCX、PPTX、图片和HTML)解析导出为Markdown或JSON格式。Docling支持高级PDF理解、OCR功能,能与LlamaIndex和LangChain等工具集成,增强文档的检索和问答能力。

Docling简介

# 5.2 Docling使用

# 5.2.1 依赖环境

实验环境:Macbook Pro 2021,M1 pro芯片,16G内存,macOS Sonoma 14.5系统,Python3.10环境

依赖安装:需要在Python3.10环境下进行安装,我试过Python3.9和Python3.11,都安装失败了。

$ pip3 install docling --index-url https://pypi.org/simple/
1

# 5.2.2 调用代码

Docling的使用非常简单,支持命令行Cli和代码调用,我这里使用后者作为示例:

# -*- coding: utf-8 -*-

from docling.document_converter import DocumentConverter

# source = "https://arxiv.org/pdf/2408.09869"  # document per local path or URL
source = "./test.docx"  
converter = DocumentConverter()
result = converter.convert(source)
print(result.document.export_to_markdown())
1
2
3
4
5
6
7
8
9

注:支持很多种方式的提取和转换,这里只是最简单的示例,详见官方文档:https://ds4sd.github.io/docling/examples/minimal (opens new window)

# 5.2.3 解析效果

首次执行脚本会自动下载模型,它的提取速度和转换效果是很不错的,对于表格处理的也比较精确。

Docling文档解析效果

局限性:1)对于没有明显层级的pdf文件,提取的md标题层级不明显。2)不支持提取图片,只能提取到图注。

# 6. MarkitDown文档解析

# 6.1 MarkitDown简介

MarkItDown是微软开源的文档处理工具,它能将PDF、PPT、Word、Excel、图像、音频、HTML等多种格式的文件转换成Markdown格式。支持OCR文字识别、语音转文字和元数据提取,适用于内容索引、数据挖掘、文档处理等场景。

MarkItDown技术原理:

  • 文件解析:用不同的解析器读取和解析各种文件格式的内容。
  • 文本提取与转换
    • 对于文档类文件(如Word、Excel、PowerPoint),将文档内容转换为纯文本,并保留结构化信息(如标题、列表等)适应Markdown格式。
    • 对于图像文件,用OCR技术(光学字符识别)识别图像中的文本,转换为文本格式。
  • 元数据处理:对于图像和音频文件,提取EXIF元数据,一种存储在文件中的标准化信息,包括文件的创建时间、作者、设备信息等。
  • 语音转录:对于音频文件,用语音识别技术将语音内容转录成文本。

# 6.2 MarkitDown使用

# 6.2.1 依赖环境

实验环境:Macbook Pro 2021,M1 pro芯片,16G内存,macOS Sonoma 14.5系统,Python3.10环境

$ pip3 install markitdown
1

# 6.2.2 调用方式

官方支持Python代码调用、命令行调用、Docker容器调用等方式。

对于文档:

# -*- coding: utf-8 -*-

from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("test.xlsx")
print(result.text_content)
1
2
3
4
5
6
7

对于图片:

# -*- coding: utf-8 -*-

from markitdown import MarkItDown
from openai import OpenAI

client = OpenAI(api_key="sk-xxx")

md = MarkItDown(llm_client=client, llm_model="gpt-4o")
result = md.convert("test.png")
print(result.text_content)
1
2
3
4
5
6
7
8
9
10

注:MarkItDown 依赖 LLM 来生成图像描述,如果没有没有提供有效的 LLM,将不会提取到任何内容。

# 6.2.3 解析效果

MarkitDown是微软开源的,它对于Office系列文档的解析效果是很不错的,而且速度很快。但对于图像、PDF等格式就没有什么优势了。

MarkitDown解析效果

# 7. ZeroX-OCR文档解析

# 7.1 ZeroX-OCR简介

# 7.1.1 基本介绍

ZeroX-OCR是一个简单易用的OCR工具,可将PDF、DOCX等文件转换为Markdown格式。它使用视觉大模型模型对每个页面进行OCR处理,并将结果聚合为最终的Markdown输出。该工具支持Node.js和Python两种语言,并提供了丰富的配置选项。

ZeroX-OCR

# 7.1.2 核心逻辑

Zerox的核心逻辑是:将输入文件(PDF、DOCX等)转换为一系列图像,然后将每个图像传递给视觉模型,请求生成Markdown,最后将所有Markdown片段聚合起来返回最终结果。

# 7.1.3 格式支持

Zerox 使用 libreoffice 和 graphicsmagick 进行文档到图像的转换,支持以下文件类型:

[
  "pdf", // Portable Document Format
  "doc", // Microsoft Word 97-2003
  "docx", // Microsoft Word 2007-2019
  "odt", // OpenDocument Text
  "ott", // OpenDocument Text Template
  "rtf", // Rich Text Format
  "txt", // Plain Text
  "html", // HTML Document
  "htm", // HTML Document (alternative extension)
  "xml", // XML Document
  "wps", // Microsoft Works Word Processor
  "wpd", // WordPerfect Document
  "xls", // Microsoft Excel 97-2003
  "xlsx", // Microsoft Excel 2007-2019
  "ods", // OpenDocument Spreadsheet
  "ots", // OpenDocument Spreadsheet Template
  "csv", // Comma-Separated Values
  "tsv", // Tab-Separated Values
  "ppt", // Microsoft PowerPoint 97-2003
  "pptx", // Microsoft PowerPoint 2007-2019
  "odp", // OpenDocument Presentation
  "otp", // OpenDocument Presentation Template
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 7.2 ZeroX-OCR使用

# 7.2.1 依赖环境

实验环境:Debian 11 x86_64 系统,8GB内存,160GB存储,Python 3.11

$ sudo apt install poppler-utils
$ conda create -n zerox python=3.11 -c conda-forge
$ conda activate zerox
$ pip3 install py-zerox
1
2
3
4

# 7.2.2 调用代码

将如下代码中的 OPENAI_API_KEY 和 OPENAI_API_BASE 换成自己的,模型选择具备视觉模态能力的即可。

from pyzerox import zerox
import os
import asyncio

model = "gpt-4o"
os.environ["OPENAI_API_KEY"] = "sk-xxx"
os.environ["OPENAI_API_BASE"] = "https://xxx.xxx.xxx/v1"

async def main():
    file_path = "./test.pdf"
    output_dir = "./output_test"
    result = await zerox(file_path=file_path, model=model, output_dir=output_dir)
    return result

result = asyncio.run(main())
print(result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 7.2.3 解析效果

对于文本、表格类的内容处理还凑合,但论文内容顺序都乱了,而且图片也全弄没了,公式也渲染不出来了,整体感觉解析效果不咋地。

而且由于需要视觉大模型API,推理成本较高,测试的这篇论文18页,消耗了483.1k的Token,大批量处理的话,不得不考虑成本问题。

ZeroX-OCR提取效果

# 8. 参考资料

[1] DeepDoc深度文档理解 from Github (opens new window)

[2] cannot import name 'cached_property' from 'nougat.utils' from Github issues (opens new window)

[3] RAG优化: 非结构化文档解析方案汇总 from 知乎 (opens new window)

[4] MinerU vs DeepDoc:集成方案+图片显示优化 from 微信公众号 (opens new window)

[5] 分享一个较好的PDF内容抽取开源项目:PDF-Extract-Kit from 知乎 (opens new window)

[6] PDF-Extract-Kit的Linux的安装教程 from Github issues (opens new window)

[7] PDF-Extract-Kit下载模型文件 from Github (opens new window)

[8] 在 macOS 上使用 PDF-Extract-Kit from Github (opens new window)

[9] 基于MinerU的PDF解析API,支持一键启动 from 微信公众号 (opens new window)

[10] 基于MinerU的PDF解析API from Github (opens new window)

[11] Alibaba出品:OmniParser通用文档复杂场景下OCR抽取 from 微信公众号 (opens new window)

[12] DocLayout-YOLO,让多样性文档布局检测更快、更准、更强 from 微信公众号 (opens new window)

[13] MarkItDown深入研究 from Software 2.0 (opens new window)

[14] TableGPT2开源,复杂表格理解不存在了 from 微信公众号 (opens new window)

[15] PDF文档解析:从挑战到实践的简明指南 from 百度智能云 (opens new window)

[16] RAGflow分片策略与文档解析器 from 微信公众号 (opens new window)

[17] 字节开源高精度文档解析大模型Dolphin from 微信公众号 (opens new window)

[18] 一站式PDF解析神器!统一封装Docling、PyMuPDF、LlamaParse from 微信公众号 (opens new window)

[19] 字节开源文档解析Dolphin,PDF解析效率提升83%,到底行不行?from 微信公众号 (opens new window)

[20] MinerU v1.3.12:支持ppocrv5模型 from 微信公众号 (opens new window)

[21] 深入拆解 MinerU 解析处理流程 from 微信公众号 (opens new window)

Last Updated: 5/28/2025, 8:57:59 PM