引言
处理pdf文件时,你是否遇到过这些难题:想复制表格却格式错乱?提取文本时段落被拆得支离破碎?手动录入pdf数据效率低下还易出错?如果你用过pypdf2、pdfminer等库,可能会发现它们在处理复杂布局(尤其是表格)时力不从心。
而 pdfplumber 的出现,完美解决了这些痛点。它是一个专注于pdf内容提取的python库,以“精准还原布局”为核心优势,能轻松提取文本、表格,甚至获取文字的位置、字体等细节信息。本文将从基础用法到实战场景,全方位讲解pdfplumber的使用,帮你彻底告别pdf处理的繁琐。
一、为什么选择pdfplumber?
在众多pdf处理库中,pdfplumber的核心竞争力在于:
- 表格提取精准:自动识别表格边框、合并单元格,提取结果保留表格结构(类似excel),远超pypdf2等库的“纯文本拼接”。
- 文本提取智能:按页面布局还原文本顺序,避免段落被无序拆分,还能获取文字的坐标、字体、大小等元数据。
- 操作简单直观:api设计简洁,几行代码即可完成提取,无需深入了解pdf底层格式。
- 支持细节控制:可指定提取区域(如只提取某页的某块内容)、过滤无效信息,灵活应对复杂pdf。
适合场景:数据分析师提取pdf报表、开发者批量处理合同文本、研究者抓取文献内容等。
二、环境准备:1分钟安装
pdfplumber是纯python库,安装无需依赖复杂的系统工具,直接用pip即可:
pip install pdfplumber
验证安装是否成功:
import pdfplumber print(pdfplumber.__version__) # 输出版本号(如 0.9.0)即成功
三、基础用法:从加载pdf到提取内容
pdfplumber的核心流程是:**加载pdf文件→获取页面→提取内容(文本/表格)**。我们从最基础的操作开始,逐步掌握核心功能。
1. 加载pdf并查看页面信息
首先需要用pdfplumber.open()加载pdf文件,然后通过pages属性获取所有页面(按页码顺序排列)。
import pdfplumber
# 加载pdf文件
with pdfplumber.open("example.pdf") as pdf:
# 查看pdf基本信息
print(f"总页数:{len(pdf.pages)}") # 输出总页数
# 获取第一页(索引从0开始)
first_page = pdf.pages[0]
# 查看页面属性
print(f"页面尺寸:{first_page.width} x {first_page.height} 像素")
print(f"页面旋转角度:{first_page.rotation}°") # 0表示正常,90/180表示旋转
print(f"是否包含图片:{len(first_page.images) > 0}")说明:用with语句加载pdf可自动释放资源,避免文件占用;pages是一个列表,pdf.pages[0]表示第1页,pdf.pages[-1]表示最后一页。
2. 提取文本:保留布局与细节
pdfplumber提取文本的核心方法是extract_text(),它会按页面布局还原文本顺序,比其他库更贴近“人眼所见”。
import pdfplumber
with pdfplumber.open("example.pdf") as pdf:
# 提取第2页文本
page = pdf.pages[1] # 第2页(索引1)
text = page.extract_text()
# 打印提取的文本(前500字符)
if text:
print("提取的文本:")
print(text[:500] + "...") # 只显示前500字符
else:
print("该页面无文本内容(可能是扫描版pdf)")进阶:获取文本的位置与样式
如果需要更详细的信息(如文字坐标、字体、大小),可用extract_words():
with pdfplumber.open("example.pdf") as pdf:
page = pdf.pages[0]
# 提取页面中所有文字的详细信息(列表 of 字典)
words = page.extract_words()
# 打印前3个文字的信息
for word in words[:3]:
print(f"文字:{word['text']}")
print(f"位置:x={word['x0']:.2f}, y={word['top']:.2f}(左上角)")
print(f"大小:宽={word['width']:.2f}, 高={word['height']:.2f}")
print(f"字体:{word.get('fontname', '未知')}, 大小={word.get('size', '未知')}\n")用途:可用于判断标题(通常字体更大)、提取特定区域的文本(如根据坐标过滤)。
3. 提取表格:自动识别结构(核心优势)
pdfplumber最强大的功能是提取表格,extract_table()和extract_tables()方法能自动识别表格边框,输出结构化的列表(每行是一个子列表),直接可用pandas转为dataframe。
示例1:提取单个表格
import pdfplumber
import pandas as pd
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[2] # 假设第3页有一个表格
# 提取表格(返回列表 of 列表)
table = page.extract_table()
if table:
# 用pandas转为dataframe(方便后续处理)
df = pd.dataframe(table[1:], columns=table[0]) # 第0行为表头
print("提取的表格:")
print(df.head()) # 打印前5行
# 保存为excel
df.to_excel("extracted_table.xlsx", index=false)
else:
print("未检测到表格")示例2:提取页面中所有表格
如果一页有多个表格,用extract_tables()(注意多了个s),返回表格列表:
with pdfplumber.open("multi_tables.pdf") as pdf:
page = pdf.pages[0]
# 提取所有表格(返回列表 of 表格)
all_tables = page.extract_tables()
print(f"页面中共检测到 {len(all_tables)} 个表格")
# 遍历每个表格并保存
for i, table in enumerate(all_tables):
if table:
df = pd.dataframe(table[1:], columns=table[0])
df.to_excel(f"table_{i+1}.xlsx", index=false)
print(f"表格 {i+1} 已保存")自定义表格提取参数
复杂表格(如无明显边框、合并单元格)可能需要调整参数,常用参数:
table_settings={"vertical_strategy": "lines", "horizontal_strategy": "lines"}:指定表格边框识别策略(lines=按线条,text=按文本间距)。snakeize=true:自动将表头转为蛇形命名(如“用户id”→“user_id”)。
示例:处理无明显边框的表格:
table = page.extract_table(
table_settings={
"vertical_strategy": "text", # 按文本垂直间距识别列
"horizontal_strategy": "text" # 按文本水平间距识别行
}
)4. 提取指定区域的内容
如果只需提取pdf中某块区域(如左上角的标题、右下角的签名),可通过坐标框选区域。
import pdfplumber
with pdfplumber.open("invoice.pdf") as pdf:
page = pdf.pages[0]
# 定义区域:(x0, top, x1, bottom),即左上角x、y和右下角x、y
# 可通过pdfplumber的可视化工具查看坐标(后文介绍)
area = (50, 50, 400, 150) # 示例区域(需根据实际pdf调整)
# 提取指定区域的文本
region_text = page.crop(area).extract_text()
print("指定区域的文本:")
print(region_text)
# 提取指定区域的表格(如果有的话)
region_table = page.crop(area).extract_table()
if region_table:
print("指定区域的表格:")
for row in region_table:
print(row)如何获取区域坐标?
推荐用pdfplumber自带的可视化工具:运行pdfplumber-cli inspect example.pdf,在浏览器中打开链接,鼠标框选区域即可显示坐标。
四、实战场景:解决实际问题
掌握基础后,我们来看几个实用场景,直接复用代码即可解决工作中的pdf处理需求。
场景1:批量提取多页pdf的文本到txt
将一个多页pdf的所有文本提取到单个txt文件,按页码分隔:
import pdfplumber
def pdf_to_txt(pdf_path, txt_path):
"""将pdf所有页面的文本提取到txt"""
with pdfplumber.open(pdf_path) as pdf, open(txt_path, "w", encoding="utf-8") as f:
for i, page in enumerate(pdf.pages, start=1):
text = page.extract_text()
if text:
f.write(f"=== 第 {i} 页 ===\n")
f.write(text + "\n\n")
print(f"文本已提取到 {txt_path}")
# 用法:提取report.pdf的文本到report.txt
pdf_to_txt("report.pdf", "report.txt")场景2:提取pdf中的所有表格并合并到excel
将pdf中所有页面的表格提取后,合并到一个excel的不同工作表:
import pdfplumber
import pandas as pd
from openpyxl import load_workbook
def extract_all_tables_to_excel(pdf_path, excel_path):
"""提取pdf中所有表格到excel的多个工作表"""
with pdfplumber.open(pdf_path) as pdf:
# 创建一个excel写入器
writer = pd.excelwriter(excel_path, engine="openpyxl")
table_count = 0 # 统计总表格数
for page_num, page in enumerate(pdf.pages, start=1):
tables = page.extract_tables()
if not tables:
continue
for i, table in enumerate(tables, start=1):
table_count += 1
# 转换为dataframe
try:
df = pd.dataframe(table[1:], columns=table[0])
except:
# 处理无表头的表格
df = pd.dataframe(table)
# 工作表名称:页面_表格序号
sheet_name = f"页{page_num}_表{i}"
# 写入excel(超过31字符会被截断,需处理)
df.to_excel(writer, sheet_name=sheet_name[:31], index=false)
print(f"已提取:{sheet_name}")
writer.close()
print(f"所有表格(共{table_count}个)已保存到 {excel_path}")
# 用法:提取所有表格到all_tables.xlsx
extract_all_tables_to_excel("multi_page_report.pdf", "all_tables.xlsx")场景3:提取发票中的关键信息(如金额、日期)
针对格式固定的发票pdf,提取指定区域的关键信息(如发票号、金额、日期):
import pdfplumber
def extract_invoice_info(pdf_path):
"""提取发票中的关键信息"""
with pdfplumber.open(pdf_path) as pdf:
page = pdf.pages[0] # 发票通常只有1页
# 定义各信息的区域(需根据实际发票调整坐标)
regions = {
"发票号": (350, 120, 500, 140), # x0, top, x1, bottom
"开票日期": (350, 150, 500, 170),
"总金额": (350, 300, 500, 320)
}
info = {}
for key, area in regions.items():
# 裁剪区域并提取文本
text = page.crop(area).extract_text()
# 清洗文本(去除空格、换行)
if text:
info[key] = text.replace("\n", "").strip()
else:
info[key] = "未找到"
return info
# 用法:提取发票信息
invoice_info = extract_invoice_info("invoice.pdf")
print("发票信息:")
for key, value in invoice_info.items():
print(f"{key}:{value}")提示:不同发票的区域坐标不同,可先用pdfplumber-cli inspect工具获取准确坐标。
场景4:处理扫描版pdf(需结合ocr)
注意:pdfplumber只能提取**文本型pdf**(由文字组成),无法直接处理**扫描版pdf**(本质是图片)。此时需先用ocr工具(如pytesseract)将图片转为文本,再用pdfplumber处理。
示例:结合ocr提取扫描版pdf的文本:
import pdfplumber
import pytesseract
from pil import image
def ocr_scanned_pdf(pdf_path, txt_path):
"""提取扫描版pdf的文本(需安装tesseract ocr)"""
with pdfplumber.open(pdf_path) as pdf, open(txt_path, "w", encoding="utf-8") as f:
for i, page in enumerate(pdf.pages, start=1):
# 将pdf页面转为图片
img = page.to_image().original # 获取pil image对象
# 用ocr识别图片中的文本
text = pytesseract.image_to_string(img, lang="chi_sim") # 中文识别
# 写入txt
f.write(f"=== 第 {i} 页 ===\n")
f.write(text + "\n\n")
print(f"扫描版pdf文本已提取到 {txt_path}")
# 用法(需先安装tesseract并配置环境变量):
# ocr_scanned_pdf("scanned_invoice.pdf", "scanned_text.txt")前置条件:需安装tesseract ocr引擎和pytesseract库,具体步骤参考tesseract官网。
五、避坑指南:常见问题与解决方案
提取的文本乱码或缺失
- 原因:pdf字体编码特殊,或文本被图片覆盖。
- 解决:尝试用
page.extract_text(x_tolerance=1, y_tolerance=1)调整 tolerance 参数;若仍乱码,可能是扫描版pdf,需结合ocr。
表格提取错乱(行列不对齐)
- 原因:表格无明显边框,或存在合并单元格。
- 解决:调整
table_settings参数,如{"vertical_strategy": "text", "horizontal_strategy": "text"};或手动指定表格区域(crop后再提取)。
大文件处理缓慢或内存溢出
- 原因:一次性加载整个pdf占用内存大。
- 解决:分页处理,提取一页释放一页资源:
with pdfplumber.open("large.pdf") as pdf:
for page in pdf.pages:
# 处理当前页...
text = page.extract_text()
# 处理完后无需保留page对象无法提取加密pdf
- 原因:pdf被加密(需密码才能打开)。
- 解决:先解密pdf(可用
qpdf工具),再用pdfplumber处理:qpdf --decrypt input.pdf output.pdf。
六、总结:pdf处理,选对工具事半功倍
pdfplumber凭借精准的文本和表格提取能力,成为python处理pdf的首选库之一。它的核心优势在于:
- 对表格的提取能力远超同类库,几乎能还原excel般的结构;
- 提供丰富的细节控制(区域提取、样式获取),灵活应对复杂场景;
- 代码简洁易上手,无需深入了解pdf底层原理。
如果你需要处理文本型pdf(尤其是包含表格的报表、发票、合同),pdfplumber能帮你节省大量手动录入时间。对于扫描版pdf,可结合ocr工具形成完整解决方案。
以上就是python使用pdfplumber提取pdf内容的操作指南的详细内容,更多关于python pdfplumber提取pdf的资料请关注代码网其它相关文章!
发表评论