pdfplumber vs PyMuPDF —— 速度、表格与许可证
pdfplumber 和 PyMuPDF 都是流行的 Python PDF 库,但两者都迫使你做出取舍。pdfplumber 擅长处理表格,却比必要速度慢 29 倍。PyMuPDF 速度很快,但被 AGPL-3.0 许可证束缚,阻碍了商业使用。本页对比两者,并说明为什么对大多数使用场景而言,PDF Oxide 是更好的选择。
简短结论: PDF Oxide 比 pdfplumber 快 29 倍,比 PyMuPDF 快 5.8 倍,采用 MIT 许可证,并在同一个库中处理文本、图像、表单、加密、Markdown 输出和 OCR。pdfplumber 至今仍领先的唯一领域,是带可视化调试的复杂表格提取。
快速对比
| pdfplumber | PyMuPDF | PDF Oxide | |
|---|---|---|---|
| 许可证 | MIT | AGPL-3.0 | MIT |
| 语言 | 纯 Python | C(MuPDF) | Rust + PyO3 |
| 平均提取时间 | 23.2ms | 4.6ms | 0.8ms |
| p99 提取时间 | 189ms | 28ms | 9ms |
| 通过率(3,830 个 PDF) | 98.8% | 99.3% | 100% |
| 文本提取 | 支持 | 支持 | 支持 |
| 字符位置 | 支持 | 支持 | 支持 |
| 表格提取 | 高级 | 基础 | 基础 |
| 图像提取 | 不支持 | 支持 | 支持 |
| 可视化调试 | 支持 | 不支持 | 不支持 |
| PDF 创建 | 不支持 | 支持 | 支持 |
| PDF 编辑 | 不支持 | 支持 | 支持 |
| Markdown 输出 | 不支持 | 不支持 | 支持 |
| HTML 输出 | 不支持 | 不支持 | 支持 |
| 表单字段 | 仅读取 | 读取 + 写入 | 读取 + 写入 |
| 加密 | 不支持 | 读取 + 写入 | 读取 + 写入 |
| 渲染 | 不支持 | 支持 | 支持 |
| OCR | 不支持 | Tesseract | 内置(PaddleOCR) |
| 安装体积 | 约 1 MB | 约 20 MB | 约 5 MB |
| Python 版本 | 3.8+ | 3.8–3.12 | 3.8–3.14 |
速度基准测试
这三个库都在同一份语料库上进行基准测试,该语料库包含来自三个独立公开测试套件(veraPDF、Mozilla pdf.js、DARPA SafeDocs)的 3,830 个 PDF。语料库涵盖了所有 PDF 规范版本(1.0–2.0)、加密文件、格式错误的文档、CJK 编码以及复杂的版式。
| 指标 | pdfplumber | PyMuPDF | PDF Oxide |
|---|---|---|---|
| 平均提取时间 | 23.2ms | 4.6ms | 0.8ms |
| p99 提取时间 | 189ms | 28ms | 9ms |
| 相对于 PDF Oxide | 慢 29 倍 | 慢 5.8 倍 | 1 倍 |
| 通过率(有效 PDF) | 98.8%(3,777/3,823) | 99.3%(3,796/3,823) | 100%(3,823/3,823) |
PyMuPDF 大约比 pdfplumber 快 5 倍,因为它将所有解析工作委托给 MuPDF 的 C 库。pdfplumber 基于 pdfminer 进行解析,再叠加自己的空间分析层——两者都是用纯 Python 编写的。PDF Oxide 通过 PyO3 在 Python 进程中直接运行的编译后 Rust 代码,处理所有解析、字体解码和文本组装,这正是它相对 PyMuPDF 快 5.8 倍、相对 pdfplumber 快 29 倍的原因。
这些数字在实践中的意义
| 工作负载 | pdfplumber | PyMuPDF | PDF Oxide |
|---|---|---|---|
| 100 个 PDF | 2.3 秒 | 0.46 秒 | 0.08 秒 |
| 1,000 个 PDF | 23 秒 | 4.6 秒 | 0.8 秒 |
| 10,000 个 PDF | 3.9 分钟 | 46 秒 | 8 秒 |
| 100,000 个 PDF | 39 分钟 | 7.7 分钟 | 80 秒 |
对于处理少量文件的一次性脚本,速度差异无关紧要。但对于每天处理数千份文档的生产流水线,39 分钟与 80 秒之间的差距会影响架构决策。
表格提取
表格提取是开发者选择 pdfplumber 而非 PyMuPDF 的主要原因。这正是 pdfplumber 真正出色的地方。
pdfplumber:结构化表格解析
pdfplumber 提供专门的表格提取功能,支持可配置的线条检测、单元格合并和可视化调试:
import pdfplumber
with pdfplumber.open("invoice.pdf") as pdf:
page = pdf.pages[0]
# Extract all tables as structured data
tables = page.extract_tables()
for table in tables:
for row in table:
print(row)
# Fine-tune detection with custom settings
tables = page.extract_tables({
"vertical_strategy": "text",
"horizontal_strategy": "lines",
"snap_tolerance": 5,
})
# Visual debugging: render page with detected table boundaries
im = page.to_image()
im.debug_tablefinder()
im.save("debug.png")
pdfplumber 返回结构化的行/列数据,并能处理合并单元格、跨列表头和无边框表格。可视化调试叠加层在处理棘手版式、调整提取参数时极为宝贵。
PyMuPDF:基础表格检测
PyMuPDF 在近期版本中加入了表格检测,但它不如 pdfplumber 的算法成熟:
import fitz
doc = fitz.open("invoice.pdf")
page = doc[0]
# PyMuPDF's built-in table finder (added in v1.23)
tabs = page.find_tables()
for table in tabs:
df = table.to_pandas() # requires pandas
print(df)
PyMuPDF 的表格提取适用于带可见边框的简单网格表格。但它在无边框版式、多级表头以及跨多行或多列的单元格上表现不佳——而这些恰恰是 pdfplumber 最擅长的场景。
PDF Oxide:Markdown 表格输出
PDF Oxide 在其结构化输出流水线中将表格转换为 Markdown 语法:
from pdf_oxide import PdfDocument
doc = PdfDocument("invoice.pdf")
# Tables are detected and converted to Markdown table format
md = doc.to_markdown(0, detect_headings=True)
print(md)
# Also available as HTML with table tags
html = doc.to_html(0)
print(html)
PDF Oxide 的表格检测对标准网格版式可用,并生成干净的 Markdown 或 HTML 输出。对于含合并单元格、无边框设计或跨列表头的复杂表格,pdfplumber 的专用算法仍然更为稳健。
表格提取小结
| 能力 | pdfplumber | PyMuPDF | PDF Oxide |
|---|---|---|---|
| 简单有边框表格 | 支持 | 支持 | 支持 |
| 无边框表格 | 支持 | 有限 | 有限 |
| 合并单元格 | 支持 | 有限 | 有限 |
| 多级表头 | 支持 | 不支持 | 不支持 |
| 可配置检测 | 支持 | 有限 | 不支持 |
| 可视化调试 | 支持 | 不支持 | 不支持 |
| 输出格式 | Python 列表 | pandas DataFrame | Markdown / HTML |
| 速度 | 慢(纯 Python) | 快 | 最快 |
如果你唯一的使用场景就是复杂表格提取,pdfplumber 是最佳工具。如果你需要表格的同时还要快速文本提取、图像提取或 PDF 创建,PDF Oxide 覆盖的范围更广。
文本提取
对于纯文本提取,两个库都能完成任务,但在速度和 API 设计上有所不同。
pdfplumber
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
text = page.extract_text()
print(text)
PyMuPDF
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
text = page.get_text()
print(text)
PDF Oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
print(text)
对于格式良好的 PDF,三者都能产生相当的文本输出。在整个语料库上,PDF Oxide 与 PyMuPDF 的文本一致率达到 99.5%,剩余 0.5% 的差异在于空白归一化和连字处理。
字符级定位
pdfplumber 和 PyMuPDF 都提供字符级位置数据,这对于空间分析、边界框检测和自定义版式重建非常重要。
pdfplumber
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
for char in page.chars[:10]:
print(f"'{char['text']}' at ({char['x0']:.1f}, {char['top']:.1f}) "
f"size={char['size']:.1f}")
PyMuPDF
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
blocks = page.get_text("dict")["blocks"]
for block in blocks:
if "lines" in block:
for line in block["lines"]:
for span in line["spans"]:
print(f"'{span['text']}' size={span['size']:.1f}")
PDF Oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
chars = doc.extract_chars(0)
for ch in chars[:10]:
print(f"'{ch.char}' at ({ch.x:.1f}, {ch.y:.1f}) size={ch.font_size:.1f}")
pdfplumber 返回带丰富元数据的逐字符字典。PyMuPDF 返回嵌套的块/行/跨度结构。PDF Oxide 返回带位置和字体数据的扁平字符对象。
许可证
对于商业项目,这是 pdfplumber 与 PyMuPDF 之间最具影响力的区别。
| pdfplumber | PyMuPDF | PDF Oxide | |
|---|---|---|---|
| 许可证 | MIT | AGPL-3.0 | MIT |
| 商业产品 | 可以 | 需要商业许可证 | 可以 |
| 闭源 SaaS | 可以 | 需要商业许可证 | 可以 |
| Docker 分发 | 可以 | 需要商业许可证 | 可以 |
| 内部工具 | 可以 | 可以 | 可以 |
| 开源项目 | 可以 | 可以(若与 AGPL 兼容) | 可以 |
PyMuPDF 的 AGPL 问题
PyMuPDF 封装了采用 AGPL-3.0 许可证的 MuPDF。如果你分发包含 PyMuPDF 的软件——包括 SaaS、Web 应用和 Docker 容器——你的代码必须以 AGPL 开源,否则你必须向 Artifex 购买商业许可证。
Artifex 不公开商业许可证的定价。你必须联系其销售团队获取报价。许可证通常按应用计费,每年续订,没有免费层级,也没有面向初创公司的例外。
pdfplumber 和 PDF Oxide 都是 MIT
pdfplumber 和 PDF Oxide 都采用 MIT 许可证。在任何项目中使用任一者——商业、专有、SaaS 或开源——都没有义务约束。如果许可证是你的首要考量,并且你正在 pdfplumber 与 PyMuPDF 之间做选择,那么 pdfplumber(或 PDF Oxide)是更安全的选择。
加密 PDF
加密处理是 pdfplumber 功能集中的一大空白,也是处理受密码保护文档的开发者常见的痛点。
pdfplumber:不支持加密
pdfplumber 根本无法打开加密或受密码保护的 PDF。如果你将加密 PDF 传给 pdfplumber,它会抛出错误。你必须先用其他工具解密文件:
import pdfplumber
# This will fail on encrypted PDFs:
with pdfplumber.open("encrypted.pdf") as pdf:
# raises pdfminer.pdfparser.PDFSyntaxError or similar
pass
常见的变通做法是先用 PyMuPDF 或 pypdf 解密文件,再传给 pdfplumber 进行表格提取——这会给你的流水线增加又一个依赖。
PyMuPDF:完整加密支持
import fitz
doc = fitz.open("encrypted.pdf")
doc.authenticate("password")
page = doc[0]
text = page.get_text()
PyMuPDF 同时支持用户密码和所有者密码、AES-128 和 AES-256 加密,并且能够创建加密 PDF。
PDF Oxide:完整加密支持
from pdf_oxide import PdfDocument
doc = PdfDocument("encrypted.pdf", password="password")
text = doc.extract_text(0)
PDF Oxide 在读取和写入两方面都能处理所有标准 PDF 加密方法(RC4、AES-128、AES-256)。无需额外依赖或预处理。
图像提取
这是 pdfplumber 功能集中的另一处空白。pdfplumber 不会从 PDF 中提取嵌入的图像。
PyMuPDF
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
for i, img in enumerate(page.get_images()):
xref = img[0]
base_image = doc.extract_image(xref)
with open(f"image_{i}.{base_image['ext']}", "wb") as f:
f.write(base_image["image"])
PDF Oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
images = doc.extract_image_bytes(0)
for i, img in enumerate(images):
with open(f"image_{i}.{img['format']}", "wb") as f:
f.write(img["data"])
如果你的流水线需要从 PDF 中同时提取文本和图像,pdfplumber 无法处理图像这一部分。为此你需要 PyMuPDF、PDF Oxide 或 pypdfium2。
Markdown 和 HTML 输出
pdfplumber 和 PyMuPDF 都不提供内置的 Markdown 或 HTML 转换。这是 PDF Oxide 独有的功能。
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
# Markdown with heading detection and table formatting
md = doc.to_markdown(0, detect_headings=True)
print(md)
# HTML with semantic tags
html = doc.to_html(0)
print(html)
对于 LLM 流水线、RAG 系统和文档转换工作流,结构化的 Markdown 输出免去了单独的转换步骤。PyMuPDF 用户通常依赖独立的 pymupdf4llm 包,而它比 PDF Oxide 的内置转换慢 69 倍。
何时选择哪个库
在以下情况选择 pdfplumber:
- 复杂表格提取是你的主要使用场景。 pdfplumber 的表格算法在处理合并单元格、无边框表格和跨列表头方面优于任何其他 Python 库。
- 你需要可视化调试。 pdfplumber 能够渲染带注释的页面图像,展示检测到的线条、字符和表格边界——这在调整棘手文档的提取时极为宝贵。
- 你想要纯 Python 方案。 没有编译依赖,凡是能运行 Python 的地方都能安装。
- 速度不是问题。 如果你每次处理少于一百个文件,平均 23ms 完全可以接受。
在以下情况选择 PyMuPDF:
- 你已经拥有商业 MuPDF 许可证,并依赖 MuPDF 特有的渲染或 SVG 导出。
- 你需要高保真渲染。 MuPDF 的渲染引擎成熟,能很好地处理复杂 PDF。
- 你的项目与 AGPL 兼容。 如果你在 AGPL 或兼容许可证下构建开源软件,PyMuPDF 的许可证不成问题。
- 你需要通过 Tesseract 进行 OCR。 PyMuPDF 内置了针对扫描文档的 Tesseract 集成。
在以下情况选择 PDF Oxide:
- 你既要速度又要广泛的功能覆盖。 平均 0.8ms 提取——比 PyMuPDF 快 5.8 倍,比 pdfplumber 快 29 倍——并在一个库中提供文本、图像、表单、创建和加密。
- 你想要 MIT 许可证而不牺牲速度。 pdfplumber 是 MIT 但慢。PyMuPDF 快但是 AGPL。PDF Oxide 既是 MIT 又快。
- 你需要 Markdown 或 HTML 输出。 面向 LLM 流水线和 RAG 系统的内置结构化转换。
- 你需要在宽松许可证下支持加密 PDF。 pdfplumber 无法处理加密。PyMuPDF 可以,但需要遵守 AGPL。PDF Oxide 在 MIT 下处理加密。
- 你想要一个库完成提取、创建和编辑。 pdfplumber 和 PyMuPDF 都需要额外工具来完成 PDF 工作流的某些部分。PDF Oxide 覆盖提取、创建、编辑、渲染和校验。
同时使用 PDF Oxide + pdfplumber:
对于既需要快速文本提取、图像提取,又需要复杂表格解析的流水线,可以用 PDF Oxide 处理通用流水线,用 pdfplumber 处理表格:
from pdf_oxide import PdfDocument
import pdfplumber
# Fast text and image extraction with PDF Oxide
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
images = doc.extract_images(0)
# Complex table extraction with pdfplumber
with pdfplumber.open("report.pdf") as pdf:
tables = pdf.pages[0].extract_tables()
安装
# pdfplumber
pip install pdfplumber
# PyMuPDF
pip install pymupdf
# PDF Oxide
pip install pdf_oxide
三者都通过 pip 安装。pdfplumber 和 PDF Oxide 采用 MIT 许可证。PyMuPDF 是 AGPL-3.0——在将其加入商业项目前,请审查其许可证影响。
结论
pdfplumber 和 PyMuPDF 都只解决了问题的一部分。PDF Oxide 解决了整个问题。
| 你最看重什么 | 最佳选择 |
|---|---|
| 极致速度 | PDF Oxide(0.8ms——比 pdfplumber 快 29 倍) |
| 复杂表格提取 | pdfplumber(可视化调试、合并单元格) |
| 宽松许可证 + 速度 | PDF Oxide——pdfplumber 是 MIT 但慢,PyMuPDF 快但是 AGPL |
| 加密 PDF | PDF Oxide 或 PyMuPDF——pdfplumber 无法解密 |
| 图像提取 | PDF Oxide 或 PyMuPDF——pdfplumber 不支持图像 |
| Markdown/HTML 输出 | PDF Oxide——唯一内置转换的库 |
| 无需 Tesseract 的 OCR | PDF Oxide——内置 PaddleOCR |
| 一个库搞定一切 | PDF Oxide——提取、创建、编辑、加密、OCR |
除非你的整个工作流都是复杂表格提取(无边框表格、合并单元格、可视化调试),否则PDF Oxide 可以取代 pdfplumber 和 PyMuPDF——更快、功能更多、采用 MIT 许可证。
10 秒上手:
pip install pdf_oxide
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0) # 29× faster than pdfplumber
md = doc.to_markdown(0) # built-in, no separate package
images = doc.extract_images(0) # pdfplumber can't do this
相关页面
- PDF Oxide vs PyMuPDF —— 含迁移指南的详细对比
- PDF Oxide vs pdfplumber —— 含代码示例的详细对比
- vs Python PDF 库 —— 所有 Python 库对比
- 性能基准测试 —— 完整语料库基准测试方法
- 从 PDF 提取表格 —— 表格提取指南
- Python 入门 —— 安装与首次提取