用Python从PDF里抽取文本的需求并不少见,比如自动化处理电子发票、批量归档合同、分析学术论文或解析政府公开文件。PDF格式的特殊之处在于,它既可能包含可直接读取的文本层,也可能只是扫描图片的集合。不同情况需要选择不同的库和处理流程,否则很容易遇到输出为空、中文乱码或顺序混乱的问题。本文按照从易到难的顺序,介绍几种稳定可行的提取方案,并给出可以直接运行的代码。

一、先分清PDF的文本层和图像层
在开始写代码之前,有必要先搞清楚PDF文件的内部结构。PDF并不是像Word那样直接存储字符流,它把文字、字体信息、位置坐标、图片等内容打包成对象。如果一份PDF由Word或排版软件直接导出,通常会保留文本层,也就是说文字可以被程序直接读取,复制粘贴也能得到正确内容。但如果PDF是扫描仪生成的,或者由图片合成,那么每一页只是一张完整图像,文字并不以字符形式存在,复制时只能选中整块图片而无法得到可编辑文本。
判断方法很直接:用任意PDF阅读器打开文件,尝试用鼠标选中某一段文字。如果能选中单个文字并复制出来,说明有文本层;如果只能框选整个页面或被识别为图片,那就是扫描版。另一种方式是检查文件大小和来源,扫描版通常体积更大。区分这两类场景,能帮助你决定下一步是调用文本提取库,还是先走OCR流程。
二、使用pdfplumber提取常规PDF文本
pdfplumber是目前处理PDF比较顺手的一个库,它基于pdfminer.six构建,对表格、字形坐标和字符位置的解析能力较好。安装命令是pip install pdfplumber。它提供的API很直观,打开一个PDF后遍历页面,每页调用extract_text即可拿到文本。下面是一个最小示例:
import pdfplumber
with pdfplumber.open("sample.pdf") as pdf:
for page in pdf.pages:
text = page.extract_text()
print(text)
这段代码会按页输出纯文本内容。如果PDF包含表格,extract_text会把表格内容也混在文本里输出,顺序可能不符合阅读习惯。这时可以使用extract_table方法单独提取表格数据,返回二维列表,再结合pandas处理会更方便。pdfplumber还支持提取单词、字符及其坐标,适合需要精确定位的场景,例如从发票中抓取特定字段。
pdfplumber的缺点是速度一般,对于几百页的大文件逐页解析会比较慢。另外它对复杂多栏排版的文本顺序有时会出现偏差,中文文档虽然大多正常,但遇到竖排文字或特殊字体时需要人工校验结果。如果你的需求只是简单抽取正文,且文件量不大,这个库足够稳定。
三、用PyMuPDF实现高性能提取
如果PDF数量多、页数厚,或者需要同时提取文本、图片和元数据,PyMuPDF(安装包名为PyMuPDF,导入时使用fitz)是更合适的选择。它的底层是MuPDF引擎,速度比纯Python实现的pdfminer系列快很多,而且内存占用更低。基本用法如下:
import fitz
doc = fitz.open("sample.pdf")
for page in doc:
text = page.get_text()
print(text)
PyMuPDF不只是提供整页文本,还能按块、按行、按单词输出。例如page.get_text("dict")会返回包含位置信息的字典结构,这对于还原版面、定位关键词坐标很有用。如果需要提取PDF中的图片,可以使用page.get_images配合doc.extract_image把原始图片保存到本地。
在实际测试中,同样一份300页的混合内容PDF,PyMuPDF提取文本可能只需要一两秒,而pdfplumber可能要几十秒甚至更久。因此做批量处理时优先考虑PyMuPDF。不过它也有自己的局限:对某些使用了未嵌入字体或者特殊编码的PDF,可能会输出空白或乱码,这时需要结合其他库交叉验证。
四、扫描版PDF的OCR处理方案
前面提到,扫描版PDF没有文本层,直接使用pdfplumber或PyMuPDF只能得到空字符串或零散乱码。面对这种情况,需要先把每一页渲染成图片,再借助OCR引擎识别文字。Python中常见的组合是pdf2image加pytesseract。pdf2image负责调用poppler将PDF逐页转成PNG或JPEG,pytesseract则调用本地的Tesseract OCR完成识别。
安装这部分依赖比纯Python库稍麻烦:除了pip安装pdf2image和pytesseract,还需要在系统里安装poppler和Tesseract可执行文件。以Windows为例,下载poppler后需要把bin目录加入PATH,Tesseract安装后也要配置路径或指定tesseract_cmd。下面是一个处理流程示例:
from pdf2image import convert_from_path
import pytesseract
pages = convert_from_path("scan.pdf", dpi=300)
for idx, img in enumerate(pages):
text = pytesseract.image_to_string(img, lang="chi_sim+eng")
print(f"第{idx+1}页:\n{text}")
dpi设置成300能在清晰度和处理时间之间取得平衡,太低会导致识别率下降,太高则图片文件过大、OCR变慢。lang参数需要提前下载对应语言包,中文使用chi_sim,英文使用eng,多个语言用加号连接。如果PDF页数很多,还可以先用PyMuPDF把页面转成图片矩阵,再交给OCR,避免反复调用外部转换工具。
OCR的准确率受扫描质量、字体大小、背景噪声影响较大。对于表格和复杂版面的扫描件,Tesseract可能无法还原原有结构,可以考虑使用商业OCR接口或专门的文档解析服务。但对普通纯文字扫描件,上述方案已经能满足搜索、归档和基础抽取需求。
五、避坑要点与选型建议
在实际项目中,有几个容易忽略的问题需要提前注意。第一是密码保护,部分PDF打开时需要口令。pdfplumber和PyMuPDF都支持传入password参数,例如fitz.open("file.pdf", password="123456")或pdfplumber.open("file.pdf", password="123456")。如果口令错误会出现异常,记得用try-except包裹。第二是字体与编码问题,某些PDF使用自定义编码或未嵌入字体,提取出来的文本可能是乱码或空白,这时可以尝试用pdfminer.six的底层API做更细粒度的解析,或者调整PDF阅读器的字体映射。
第三是文本顺序和多栏排版。提取出的文本默认按照PDF内部对象顺序输出,不一定符合视觉阅读顺序。如果不做处理,双栏论文的左右栏文字可能交错拼接,导致内容难以理解。pdfplumber通过字符坐标排序可以部分缓解,PyMuPDF的get_text("blocks")也会保留块的位置信息,可以自己实现排序逻辑。
选型上可以遵循一个简单原则:少量普通PDF且需要表格解析时选pdfplumber;大批量或性能敏感时选PyMuPDF;扫描件必须走OCR路线;如果对排版还原要求极高,考虑使用更专业的解析服务或自行基于坐标开发。不要一开始就追求一个库解决所有问题,理解PDF的生成方式和内容结构,比盲目尝试多个库更高效。
PythonPDF文本提取pdfplumber修改时间:2026-09-22 03:45:42