Python 提取 PDF 文本:3 个库怎么选
用 Python 提取 PDF 文本,看起来像是件很简单的事;但真正做过的人都知道,实际情况往往充满例外:版式错乱、阅读顺序不对、还有顽固的图片型文档。这篇指南不讲空话,先直接对比几种常用的 Python PDF 文本提取库,帮你快速判断项目该用哪一个。

接下来,我们会用代码分别演示 3 个非常实用的库:PyPDF2、pdfplumber 和 PyMuPDF(Fitz)。内容会从基础的 PDF 读取文本,一直讲到复杂表格的处理方式。我们还会重点解决最棘手的一类文件:需要 OCR 识别的扫描版 PDF,并给出一种不依赖复杂本地环境的实用方案。读完后,你不仅能拿到可直接改用的代码,也能明确不同场景下该怎么选库、怎么搭建稳定的 PDF 自动化处理流程。
快速结论:Python 提取 PDF 文本用哪个库
在看代码之前,先快速过一遍这几个主流方案。到底选哪个,核心取决于你的需求更偏向速度、上手难度,还是版面与结构分析能力。
| 库 | 最适合的场景 | 版面/表格处理 | 性能 | 易用性(1-5) |
|---|---|---|---|---|
| PyPDF2 | 简单的纯文本文档;基础 PDF 操作(合并/拆分) | 较弱(只能提取文本流,没有位置数据) | 中等 | 5 |
| pdfplumber | Python 提取 PDF 表格;处理结构化版式文档 | 很强(可提供文本、线条、矩形的坐标信息) | 较慢 | 4 |
| PyMuPDF (Fitz) | 高速批量处理;处理图片和批注 | 良好(可提取带基础位置信息的文本) | 很强(速度最快) | 4 |
一句话建议: 最简单的 PDF 文本提取,先用 PyPDF2。只要文档里出现表格,优先换成 pdfplumber。如果你最看重处理速度,就选 PyMuPDF。
开始前准备:配置 Python 环境
为了让项目依赖保持干净、避免包冲突,建议始终在虚拟环境里操作。这不是可选项,而是稍微正式一点的 Python 项目都应该遵守的基本实践。
下面是在终端里完成环境配置的方法:
- 创建虚拟环境:
# 在 macOS/Linux 上
python3 -m venv pdf_env
# 在 Windows 上
python -m venv pdf_env
```
2. **激活虚拟环境:**
```plaintext
# 在 macOS/Linux 上
source pdf_env/bin/activate
# 在 Windows 上
.\pdf_env\Scripts\activate
```
激活后,你的终端提示符里应该会看到 `(pdf_env)`。
3. **安装相关库:** 我们把这次要对比的 3 个库都装上,后面你就可以直接跟着代码一起测试。
```plaintext
pip install pypdf2 pdfplumber pymupdf
```
到这里,运行下面的代码示例所需环境就准备好了。
---
## 方法 1:用 PyPDF2 提取 PDF 文本
PyPDF2 是处理 PDF 基础操作时最常用的库之一。它简单直接、使用历史长,很适合处理“原生 PDF”——也就是文本可以直接选中,而不是嵌在图片里的那类文件。如果你的文档是普通报告、文章,或者文本型导出文件,那么用 PyPDF2 读取 PDF 内容,通常只需要很少的代码就够了。
它的主要限制也很明显:PyPDF2 读取的是 PDF 内部的文本流,这和人眼看到的阅读顺序不一定一致,尤其是在多栏排版里更容易出问题。它也不理解表格结构,遇到表格时,往往会把所有单元格内容直接拼成一团。
下面是一个用 PyPDF2 提取 PDF 全部文本的简单示例:
```python
# requirements: pip install pypdf2
import PyPDF2
def extract_text_with_pypdf2(pdf_path):
"""
使用 PyPDF2 库从 PDF 文件中提取文本。
参数:
pdf_path (str): PDF 文件路径。
返回:
str: 提取出的文本内容,或错误信息。
"""
try:
with open(pdf_path, 'rb') as file:
reader = PyPDF2.PdfReader(file)
num_pages = len(reader.pages)
print(f"总页数: {num_pages}")
full_text = ""
for page_num in range(num_pages):
page = reader.pages[page_num]
full_text += page.extract_text() + "\n"
return full_text
except FileNotFoundError:
return f"错误:未找到文件 {pdf_path}。"
except Exception as e:
return f"发生了意外错误:{e}"
# --- 使用示例 ---
pdf_file = 'path/to/your/document.pdf'
extracted_text = extract_text_with_pypdf2(pdf_file)
if "Error" not in extracted_text:
print("--- 提取结果 ---")
print(extracted_text)
else:
print(extracted_text)
这段脚本在处理简单的单栏文本时效果很好。但如果你拿它去解析带有规整表格的财务报表,会发生什么?结果通常是一堆混在一起的文字和数字,几乎没有结构可言。这正是下一个库更擅长解决的问题。
方法 2:用 pdfplumber 提取 PDF 表格和版面内容
如果你的任务是提取结构化数据,pdfplumber 往往更合适。它构建在 pdfminer.six 之上,能更细粒度地读取 PDF 页面中的几何信息。它不仅能识别字符,还能识别线条、矩形等页面元素,并且内置了非常实用的表格检测与提取方法。
这对数据分析和业务自动化场景非常有用。比如你要从公司的 PDF 财报里提取季度业绩数据,用 PyPDF2 往往得靠繁琐的字符串解析;而用 pdfplumber,通常可以直接拿到干净的二维列表,再顺手转成 Pandas DataFrame。
pdfplumber 在处理结构化数据时比 PyPDF2 更强,核心原因在于它不仅提取原始文本流,还会分析页面的视觉布局。 它能判断哪些文本是按行列对齐的,哪些区域由线条分隔,因此更适合提取表格和规则版面。
下面演示如何从 PDF 页面中提取表格:
# 依赖安装:pip install pdfplumber
import pdfplumber
import pandas as pd
def extract_tables_with_pdfplumber(pdf_path, page_number=0):
"""
使用 pdfplumber 从 PDF 的指定页面提取所有表格。
参数:
pdf_path (str): PDF 文件路径。
page_number (int): 要提取表格的页码(从 0 开始计数)。
返回:
list of pandas.DataFrame: 列表中的每个元素都是一个 DataFrame,
对应页面中识别到的一张表格。
"""
tables = []
try:
with pdfplumber.open(pdf_path) as pdf:
if page_number >= len(pdf.pages):
print(f"错误:第 {page_number} 页超出范围。该 PDF 共 {len(pdf.pages)} 页。")
return tables
page = pdf.pages[page_number]
# 这里的关键方法是 .extract_tables()
extracted_tables = page.extract_tables()
for table_data in extracted_tables:
# 将二维列表转换为 pandas DataFrame
df = pd.DataFrame(table_data[1:], columns=table_data[0])
tables.append(df)
return tables
except FileNotFoundError:
print(f"错误:未找到文件 {pdf_path}。")
return tables
except Exception as e:
print(f"发生了未预期的错误:{e}")
return tables
# --- 使用示例 ---
# 运行此示例前还需要安装 pandas:pip install pandas
pdf_file_with_table = 'path/to/your/report.pdf'
all_tables = extract_tables_with_pdfplumber(pdf_file_with_table, page_number=0)
if all_tables:
print(f"第 0 页共找到 {len(all_tables)} 张表格。")
for i, table_df in enumerate(all_tables):
print(f"\n--- 表格 {i+1} ---")
print(table_df)
else:
print("指定页面未找到表格。")
这种高精度的代价是速度。pdfplumber 需要对页面做更多版面分析,因此天然会比那些只负责导出文本的库更慢。
方法 3:用 PyMuPDF(Fitz)高速提取 PDF 文本
如果你需要快速处理几百甚至上千个 PDF,性能往往就是决定因素。这正是 PyMuPDF 的强项。它在代码里通过 fitz 导入,底层绑定的是轻量级 C 库 MuPDF,因此速度非常出色。
我之前做过一个项目,需要批量处理几千份多页法律文档。最开始用 pdfplumber 写的脚本,预估要跑好几个小时;后来换成 PyMuPDF,整体运行时间压到了 30 分钟以内,速度差距就是这么明显。
除了快,PyMuPDF 的功能也很全面。它可以把页面渲染成图片(这对 OCR 流程尤其关键)、提取嵌入图片,还能处理批注。虽然它不像 pdfplumber 那样开箱即用地提取表格,但在原始文本提取速度上几乎没有对手。
下面是用 PyMuPDF 快速提取文本的写法:
# 依赖安装:pip install PyMuPDF
import fitz # PyMuPDF 库
def extract_text_with_pymupdf(pdf_path):
"""
使用高性能的 PyMuPDF(Fitz)库从 PDF 文件中提取文本。
参数:
pdf_path (str): PDF 文件路径。
返回:
str: 提取到的文本内容,或错误信息。
"""
try:
doc = fitz.open(pdf_path)
full_text = ""
for page in doc:
# 核心方法是 .get_text()
full_text += page.get_text() + "\n"
doc.close()
return full_text
except FileNotFoundError:
return f"错误:未找到文件 {pdf_path}。"
except Exception as e:
# PyMuPDF 可能抛出特定错误,例如 fitz.fitz.FitzError
return f"PyMuPDF 处理时出错:{e}"
# --- 使用示例 ---
pdf_file = 'path/to/your/document.pdf'
fast_extracted_text = extract_text_with_pymupdf(pdf_file)
if "Error" not in fast_extracted_text:
print("--- 提取结果(高速方式)---")
print(fast_extracted_text)
else:
print(fast_extracted_text)
如果处理的是可选中文本的 PDF,单看吞吐量,PyMuPDF 基本就是首选。
特殊情况:扫描版 PDF 需要配合 OCR 识别
你可能会问:如果上面这些方法都不生效怎么办?如果你把这些代码直接用在扫描文档上——比如合同照片生成的 PDF,或者扫描后的书页——通常只会得到一个空字符串。
原因很简单:这类 PDF 根本没有文本层,里面存的是图片,不是字符。要解决这个问题,就必须用 OCR(光学字符识别)去“读”图片,再把它转换成机器可处理的文字。
Python 里常见的方案是 pytesseract,它是 Google Tesseract OCR 引擎的封装。不过它也有一个很现实的麻烦:你需要先在系统里单独安装 Tesseract(例如在 Mac 上通过 brew 安装,或在 Windows 上运行安装程序),还要确保 Python 能找到对应的可执行文件。这个配置过程并不省心,尤其是在把代码部署到服务器,或者需要分享给同事时,环境问题很容易冒出来。
替代方案:先用免代码工具预处理复杂 PDF
如果你赶时间,或者不想折腾 OCR 依赖,一个更省事的做法是先把 PDF 文本提取交给专门的工具处理。这样可以把复杂的 OCR 问题和你的 Python 主逻辑拆开。
像 Lynote AI PDF 文本提取工具 这样的 AI 工具,就很适合拿来做前置处理。你可以先上传那些难处理的扫描版 PDF,由它在后台完成 OCR 识别,再输出干净的文本,后续直接喂给你的脚本即可。对于一次性任务,或者只需要处理少量棘手文件的场景,这种方式尤其省时间。
整个流程其实很简单:
- 上传 PDF 文件。 打开 Lynote 工作区,在“Upload File”标签页中,你可以直接拖拽 PDF 上传,或从电脑中选择文件。无论是文本型 PDF,还是扫描图片型 PDF,都可以处理。
- 提取 PDF 文本。 文件上传完成后,点击“Create Note”按钮。Lynote 的 AI 引擎会开始处理文档;如果检测到这是图片型 PDF,会自动调用 OCR,并生成一份干净、可搜索的文本内容。
- 复制提取结果。 当文本出现在编辑器中后,你可以先快速检查一遍,做一些小修正,然后点击复制按钮,把全部内容复制出来。这样文本就进入剪贴板了,可以直接粘贴到你的 Python 脚本里,作为字符串变量继续处理。


这样做的好处是,你可以把精力放在数据分析和业务逻辑上,而不是本地 OCR 环境的搭建、依赖管理和报错处理上。
常见坑点与进阶技巧
用 Python 提取 PDF 文本时,很少能一次做到完全无误。下面这些问题,基本都是实战里经常会遇到的:
- 字符编码问题: 你可能会遇到
UnicodeDecodeError。这类问题常见于较老的 PDF,或由一些冷门软件生成的文件。大多数现代库都能较好处理UTF-8,但如果库本身支持,手动指定编码有时也能解决问题。 - 带密码保护的 PDF: 如果 PDF 打开时需要密码,这些库默认都无法直接读取。你必须在打开文件时传入密码。例如:
PyPDF2.PdfReader(file, password='your_password')。 - 格式信息丢失: 要注意,Python 读取 PDF 内容时,提取出来的通常只是纯文本,像加粗、斜体、字号、颜色这类格式几乎都会丢失。你拿到的是原始文字内容,不是页面的视觉效果。
- 多栏文本顺序混乱: 前面提到过,PyPDF2 在处理多栏排版(比如论文)时,常会把不同栏的内容混在一起。这是因为它对页面结构理解有限。相比之下,
pdfplumber更擅长处理这类情况,因为它会结合页面几何位置来区分文本。
实战建议: 写好脚本后,一定要先拿一批有代表性的 PDF 样本做测试。某个方案在一份 PDF 上效果很好,换一个来源的文件,可能就完全失效。
常见问题
为什么我从表格里提取出来的文本变成了一整串乱序内容?
这正是不做版面分析的库(比如 PyPDF2)最典型的问题。它们是按文件内部存储的文本流顺序去读取内容,而这个顺序往往和你肉眼看到的行列结构并不一致。想解决这个问题,就要用支持版面识别的库,比如 **pdfplumber**。它本身就是为识别表格数据而设计的。
Python 能提取 PDF 页面某个指定区域的文本吗?
可以,但前提是你使用的库要支持坐标信息。pdfplumber 和 PyMuPDF 都很适合做这件事。以 pdfplumber 为例,你可以用 .crop((x0, top, x1, bottom)) 先框定一个区域,然后只对这个裁剪范围执行 .extract_text() 或 .extract_tables()。
为什么扫描版 PDF 提取出来是空的?
因为你的 PDF 里存的是文字图片,而不是真正的文本数据。常规的 Python PDF 文本提取库并不能直接“读懂”图片。这种情况下,你需要用 OCR 识别 PDF。你可以在本地配置 pytesseract 这类 OCR 引擎,也可以先用 Lynote 这样的预处理工具,把扫描版 PDF 转成干净文本,再交给 Python 继续处理。
多语言 PDF 该怎么处理?
像 PyMuPDF 和 pdfplumber 这样的现代库,通常都能较好支持 Unicode,因此处理大多数语言的文本问题不大。真正的难点通常出现在 OCR 阶段。比如 Tesseract 就要求你提前下载并指定要使用的语言包(例如 -l eng+fra 表示同时识别英文和法文)。
如何选择合适的 Python PDF 提取工具
做 Python 提取 PDF 文本时,并不存在一个适合所有场景的“最佳库”。真正该选哪个,取决于你的 PDF 文件类型,以及项目最终要达到什么目标。
你可以按下面这个思路快速判断:
- 如果你的 PDF 是简单的文本型文档,只需要把原始文字内容读出来,PyPDF2 通常是最容易上手、实现成本最低的选择。
- 如果你的 PDF 里有表格或结构化排版,而你还需要把内容进一步解析成数据(例如导入数据库或 Pandas DataFrame),那 pdfplumber 基本是首选,尤其适合 Python 提取 PDF 表格 这类场景。
- 如果你要批量处理大量文件,并且最看重执行速度,那么 PyMuPDF (Fitz) 往往是性能最强、效率最高的方案。
- 如果你处理的是扫描版、图片型 PDF,那就必须走 OCR 流程。要是你不想折腾本地环境配置,通常更务实的做法是先用外部工具把文件预处理成干净文本,再导入 Python 环境继续分析。
建议先从能满足需求的最简单方案开始;如果后续遇到更复杂的版面、表格或扫描件,再切换到更强的工具也不迟。


