你一定遇到过:收到一份 PDF 报告,领导让你把里面的关键数据整理出来。你打开 PDF,一页一页复制粘贴,格式乱了还要手动调。几百页的文档,复制到怀疑人生。
这篇教你用 Python 批量提取 PDF 文本,支持单页、全文、按页码范围、批量文件夹四种模式,复制代码直接用。
01 为什么选 pdfplumber 做文本提取
Python 提取 PDF 文本的方案有好几种,各有优劣:
PyPDF2:能提取文本,但对复杂排版(多栏、表格内嵌文字)处理较差,经常出现文字顺序错乱。
pdfplumber:基于 pdfminer.six 开发,文本提取精度更高,能保留页码、位置信息,还能顺便提取表格。本文主力推荐。
pdfminer.six:pdfplumber 的底层库,功能强但 API 偏底层,用起来麻烦。
安装(上一篇已装过,这里确认一下):
02 基础提取:单份 PDF 全文提取
先从最简单的开始,把一份 PDF 的所有文字提取出来:
import pdfplumberpdf_path = "report.pdf"with pdfplumber.open(pdf_path) as pdf: full_text = "" for page in pdf.pages: text = page.extract_text() if text: full_text += text + "\n\n" print(f"共 {len(pdf.pages)} 页") print(f"提取到 {len(full_text)} 个字符") print("--- 前500字预览 ---") print(full_text[:500])
关键说明:
pdfplumber.open() 用上下文管理器(with 语句),自动释放资源,这是最佳实践。page.extract_text()返回当前页的文本字符串,空白页返回 None,所以要加判断。
03 导出为 TXT 文件
提取出来的文本要保存成文件,方便后续处理:
import pdfplumberpdf_path = "report.pdf"output_path = "report_text.txt"with pdfplumber.open(pdf_path) as pdf: full_text = "" for page_num, page in enumerate(pdf.pages, start=1): text = page.extract_text() if text: full_text += f"===== 第 {page_num} 页 =====\n{text}\n\n"with open(output_path, "w", encoding="utf-8") as f: f.write(full_text)print(f"文本已导出到: {output_path}")
注意必须指定 encoding="utf-8",否则 Windows 下默认 GBK 编码,中文会乱码。
04 按页码范围提取
有时候只需要某几页的内容,比如合同的第 3 到第 5 页:
import pdfplumberpdf_path = "contract.pdf"start_page = 3 # 从第3页开始end_page = 5 # 到第5页结束with pdfplumber.open(pdf_path) as pdf: # pdfplumber页码从0开始,所以要减1 for page_num in range(start_page - 1, end_page): page = pdf.pages[page_num] text = page.extract_text() print(f"===== 第 {page_num + 1} 页 =====") print(text) print()
05 批量提取整个文件夹
这才是职场真正的刚需:一个文件夹里几十上百份 PDF,全部提取文本保存。
import pdfplumberimport ospdf_dir = "./pdf_files"output_dir = "./extracted_text"# 创建输出文件夹os.makedirs(output_dir, exist_ok=True)# 获取所有PDF文件pdf_files = [f for f in os.listdir(pdf_dir) if f.lower().endswith(".pdf")]success_count = 0fail_count = 0for filename in pdf_files: pdf_path = os.path.join(pdf_dir, filename) txt_filename = os.path.splitext(filename)[0] + ".txt" txt_path = os.path.join(output_dir, txt_filename) try: with pdfplumber.open(pdf_path) as pdf: full_text = "" for page_num, page in enumerate(pdf.pages, start=1): text = page.extract_text() if text: full_text += f"===== 第 {page_num} 页 =====\n{text}\n\n" with open(txt_path, "w", encoding="utf-8") as f: f.write(full_text) print(f"✓ {filename} → {txt_filename}") success_count += 1 except Exception as e: print(f"✗ {filename} 失败: {str(e)}") fail_count += 1print(f"\n完成!成功 {success_count} 个,失败 {fail_count} 个")
为什么加 try-except? 批量处理时,某个 PDF 损坏、加密、格式异常很常见。加异常捕获保证一个文件失败不会中断整个批量任务,最后还能统计成功率。
06 进阶:提取带位置信息的文本
普通提取只能拿到文字内容,但如果你需要知道 "某段文字在页面的哪个位置"(比如做数据定位、区域提取),用 extract_words():
import pdfplumberwith pdfplumber.open("report.pdf") as pdf: page = pdf.pages[0] words = page.extract_words() # 每个word是一个字典,包含文字和坐标 for w in words[:10]: # 看前10个词 print(f"文字: {w['text']}, x0: {w['x0']:.1f}, top: {w['top']:.1f}")
返回的每个词包含:text(文字)、x0(左边界)、x1(右边界)、top(上边界)、bottom(下边界)。有了坐标信息,你可以精确提取页面某个区域的文字。
按区域提取文本示例:
import pdfplumberwith pdfplumber.open("report.pdf") as pdf: page = pdf.pages[0] # 只提取页面上半部分 cropped = page.crop((0, 0, page.width, page.height / 2)) text = cropped.extract_text() print(text)
crop() 的参数是 (x0, top, x1, bottom),单位是 PDF 的 point(1/72 英寸)。这个功能在处理固定格式的表单、发票时特别有用。
07 常见坑与解决方案
坑 1:提取出来的文字顺序错乱
多栏排版的 PDF,pdfplumber 默认按阅读顺序提取,但偶尔会出问题。可以尝试 page.extract_text(x_tolerance=3, y_tolerance=3),调整容差参数。
坑 2:提取出来是空的
大概率是扫描版 PDF(图片型 PDF)。这种 PDF 没有文字层,需要 OCR 识别。可以用 pytesseract+PIL,或者调用百度 / 腾讯 OCR API。
坑 3:特殊字符乱码
某些 PDF 使用了自定义字体编码,提取出来会是乱码。这种情况比较难处理,可以尝试用 pdfminer.six 的底层 API 指定字符映射,或者换用 OCR 方案。
坑 4:密码保护的 PDF
加密 PDF 无法直接提取,会报错。需要先解密,第④篇专门讲。
写在最后
文本提取是 PDF 自动化中最基础也最实用的技能。掌握了批量提取,你就可以把几百份 PDF 的内容快速变成可搜索、可分析的文本数据。