项目简介
pdfplumber 项目(基于pdfminer.six开发),支持解析PDF文件,获取每个文本字符、矩形和线条的详细信息。此外还支持表格提取和可视化调试。
对于机器生成的PDF而言效果最佳,不适用于扫描得到的PDF。
支持:Python 3.8~3.11
加载PDF文件
处理PDF 请调用pdfplumber.open(x)方法,其中x可以是:
- PDF 文件路径
- 作为字节加载的文件对象
- 作为字节加载的类似文件的对象
高级加载参数
要加载受密码保护的PDF,请传递password关键字参数,例如:pdfplumber.open("file.pdf", password="test")
pdfplumber.PDF 类(Top-level)
pdfplumber.PDF类表示一个独立的PDF文件,两个主要成员变量:
| 属性 | 描述 |
|---|---|
.metadata | 一个由PDF的 Info 尾部信息中的元数据键/值对组成的字典。通常包括 "CreationDate," "ModDate," "Producer," 创建时间 修改时间 发行商等等。 |
.pages | 包含每个已加载页面的 pdfplumber.Page 实例的列表。 |
一个主要成员方法:处理大文件时需要考虑内存
| 方法 | 描述 |
|---|---|
.close() | 默认情况下,Page 对象会缓存其布局和对象信息,以避免重新处理。然而,在解析大型PDF时,这些缓存的属性可能需要大量内存。你可以使用此方法来清除缓存并释放内存 |
import pdfplumber
pdf = pdfplumber.open("The_Old_Man_of_the_Sea.pdf")
print(pdf.metadata)
输出内容
{'CreationDate': "D:20060717205532+08'00'", 'Subject': 'For Personal Learning!', 'Author': 'Asiaing.com', 'Creator': 'PScript5.dll Version 5.2', 'Producer': 'Acrobat Distiller 7.0.5 (Windows)', 'ModDate': "D:20060717210222+08'00'", 'Title': 'Hemingway, Ernest - The Old Man and the Sea'}
pdfplumber.Page 类
import pdfplumber
pdf = pdfplumber.open("The_Old_Man_of_the_Sea.pdf")
pages = pdf.pages
print(pages[0].page_number)
print(pages[0].width, pages[0].height)
## 输出
1
405.0 591.0
pdfplumber.Page 类是 pdfplumber 的核心,表示PDF文件中一页单独的内容。
当我们使用 pdfplumber 时,大部分操作都会围绕这个类展开。
主要成员变量如下:
| 属性 | 描述 |
|---|---|
.page_number | 顺序页码,从第一页开始为 1,第二页为 2,以此类推。 |
.width | 页面的宽度。 |
.height | 页面的高度。 |
.objects / .chars / .lines / .rects / .curves / .images | 这些属性都是列表,每个列表包含页面上嵌入的每个此类对象的一个字典。 |
提取单页文本
获取单页文本
import pdfplumber
pdf = pdfplumber.open("The_Old_Man_of_the_Sea.pdf")
pages = pdf.pages
p1_text = pages[1].extract_text()
print(p1_text)
# 获取单页文本(保留布局)
p1_text = pages[1].extract_text(layout=True)
print(p1_text)
提取单页表格
pdfplumber 对表格提取的方法大量借鉴了 Anssi Nurminen 的硕士论文,并受到 Tabula 的启发。
它的工作原理如下:
- 对于任何给定的PDF页面,找到那些(a)明确定义的线条和/或(b)由页面上单词的对齐方式暗示的线条。
- 合并重叠的,或几乎重叠的,线条。
- 找到所有这些线条的交点。
- 找到使用这些交点作为顶点的最精细的矩形集合(即,单元格)。
- 将连续的单元格分组成表格。
表格提取方法
pdfplumber.Page 对象可以调用以下方法:
| 方法 | 描述 |
|---|---|
.find_tables(table_settings={}) | 返回一个 Table 对象的列表。Table 对象提供对 .cells,.rows,和 .bbox 属性的访问,以及 .extract(x_tolerance=3, y_tolerance=3) 方法。 |
.find_table(table_settings={}) | 类似于 .find_tables(...),但返回页面上 最大 的表格,作为一个 Table 对象。如果多个表格的大小相同 —— 以单元格数量衡量 —— 此方法返回最接近页面顶部的表格。 |
.extract_tables(table_settings={}) | 返回从页面上找到的 所有 表格中提取的文本,表示为一个列表的列表的列表,结构为 table -> row -> cell。 |
.extract_table(table_settings={}) | 返回从页面上 最大 的表格中提取的文本(参见上面的 .find_table(...)),表示为一个列表的列表,结构为 row -> cell。 |
.debug_tablefinder(table_settings={}) | 返回 TableFinder 类的一个实例,可以访问 .edges,.intersections,.cells,和 .tables 属性。 |
test.pdf 文件内容
代码示例
import pdfplumber
pdf = pdfplumber.open("test.pdf")
pages = pdf.pages
# 获取单页表格
p1_table = pages[0].extract_table()
print(p1_table)
# 输出内容
[['Fruit', 'Color', 'Price (USD)'], ['Apple', 'Red', '1.20'], ['Banana', 'Yellow', '0.50'], ['Orange', 'Orange', '0.80'], ['Strawberry', 'Red', '2.50'], ['Blueberry', 'Blue', '3.00'], ['Kiwi', 'Green', '1.00'], ['Mango', 'Orange', '1.50'], ['Grape', 'Purple', '2.00']]
提取页面图像
pdfplumber.Page 对象没有 extract_images 方法,所以不能直接从 PDF 页面中提取图像。
但是,可以通过页面操作来截取和获取图像,pdfplumber.Page类相关成员变量如下:
| 属性 | 描述 |
|---|---|
.width | 页面的宽度。 |
.height | 页面的高度。 |
.objects / .chars / .lines / .rects / .curves / .images | 这些属性都是列表,每个列表包含页面上嵌入的每个此类对象的一个字典。 |
相关成员方法:
| 方法 | 描述 |
|---|---|
.crop(bounding_box, relative=False, strict=True) | 返回裁剪到边界框的页面版本,边界框应表示为4元组,值为 (x0, top, x1, bottom)。裁剪的页面保留至少部分在边界框内的对象。如果对象只部分在框内,其尺寸将被切割以适应边界框。如果 relative=True,则边界框是从页面边界框的左上角偏移计算的,而不是绝对定位。(请参见 Issue #245 以获取视觉示例和解释。)当 strict=True(默认值)时,裁剪的边界框必须完全在页面的边界框内。 |
.within_bbox(bounding_box, relative=False, strict=True) | 类似于 .crop,但只保留 完全在 边界框内的对象。 |
.outside_bbox(bounding_box, relative=False, strict=True) | 类似于 .crop 和 .within_bbox,但只保留 完全在 边界框外的对象。 |
.filter(test_function) | 返回只有 test_function(obj) 返回 True 的 .objects 的页面版本。 |
原始pdf页面
裁剪后的图片
import pdfplumber
pdf = pdfplumber.open("test.pdf")
pages = pdf.pages
img = pages[1].images[0]
bbox = (img["x0"], img["top"], img["x1"], img["bottom"])
cropped_page = pages[1].crop(bbox)
# 可视化裁剪后的第二页
print(cropped_page.to_image())