pdfplumber - pdf 数据提取

发布于:2024-08-23 ⋅ 阅读:(62) ⋅ 点赞:(0)

一、关于 pdfplumber


Plumb 一个 PDF 以获取每个文本字符、矩形和线条的详细信息。另外:表格提取和可视化调试。

在机器生成 而不是 扫描的PDF上 工作得最好。

pdfminer.six 基础上开发。

目前在 Python 3.8, 3.9, 3.10, 3.11进行了测试

本文件的翻译版本为:中文(by@hbh112233abc)

要报告bug或请求功能,请提交问题要提出问题或请求特定PDF的帮助,请使用讨论论坛


安装

pip install pdfplumber

二、命令行界面


1、基本示例

curl "https://raw.githubusercontent.com/jsvine/pdfplumber/stable/examples/pdfs/background-checks.pdf" > background-checks.pdf
pdfplumber < background-checks.pdf > background-checks.csv

输出将是一个CSV,其中包含有关PDF中每个字符、行和矩形的信息。


2、选项

参数 描述
--format [format] csvjsonjson格式返回更多信息;它包括PDF级别和页面级别的元数据,以及字典嵌套属性。
--pages [list of pages] 以空格分隔, 1索引页面列表或连字符页面范围。
例如,1, 11-15,它将返回第1、11、12、13、14和15页的数据。
--types [list of object types to extract] 可选择 charrectlinecurveimageannot等等。默认为所有可用。
--laparams JSON格式的字符串( 例如,'{"detect_vertical": true}')传递给pdfplumber.open(..., laparams=...)
--precision [integer] 四舍五入浮点数的小数位数。默认为不四舍五入。

三、Python库


1、基本示例

import pdfplumber

with pdfplumber.open("path/to/file.pdf") as pdf:
    first_page = pdf.pages[0]
    print(first_page.chars[0])

2、加载PDF

要开始使用PDF,请调用pdfplumber.open(x),其中x可以是:

  • PDF文件的路径
  • 文件对象,以字节形式加载
  • 类似文件的对象,以字节形式加载

这个open方法返回一个pdfplumber.PDF类的实例。

要加载受密码保护的PDF,请传递password关键字参数,例如pdfplumber.open("file.pdf", password = "test")

要将布局分析参数设置到pdfminer.six的布局引擎,请传递laparams关键字参数,例如pdfplumber.open("file.pdf", laparams = { "line_overlap": 0.7 })

预规范化Unicode文本,传递unicode_norm=...,其中...四种Unicode规范化形式之一:"NFC""NFD""NFKC""NFKD"

默认情况下,无效的元数据值被视为警告。如果不是这样,请将strict_metadata=True传递给open方法,如果无法解析元数据,pdfplumber.open将引发异常。


3、pdfplumber.PDF

顶级的pdfplumber.PDF类表示单个PDF,并具有两个主要属性:

属性 描述
.metadata 元数据键/值对的字典,从PDF的Info预告片中提取。通常包括“CreationDate”、“ModDate”、“Producer”等。
.pages 每个加载的页面包含一个pdfplumber.Page实例的列表。

… 并且还具有以下方法:

方法 描述
.close() 调用此方法会在每个页面上调用Page.close(),并且还会关闭文件流(除了流是外部的情况,即已经打开并直接传递给pdfplumber)。

4、pdfplumber.Page

pdfplumber.Page类是pdfplumber的核心。

您将使用pdfplumber做的大多数事情都将围绕这个类进行。

它具有以下主要属性:

属性 描述
.page_number 顺序页码,第一页从1开始,第二页从2开始,依此类推。
.width 页面宽度。
.height 页面高度。
.objects/.chars/.lines/
.rects/.curves/.images
这些属性中的每一个都是一个列表,每个列表都包含一个字典,用于嵌入在页面上的每个这样的对象。有关详细信息,请参阅下面的“对象”。

…以及这些主要方法:

方法 描述
.crop(bounding_box, relative=False, strict=True) 返回裁剪到边界框的页面版本,该版本应表示为带有值的4元组(x0, top, x1, bottom)
裁剪的页面保留至少部分位于边界框内的对象。
如果对象仅部分位于框内,则对其尺寸进行切片以适应边界框。
如果relative=True,边界框的计算方法是与页面边界框左上角的偏移量,而不是绝对定位。(请参阅问题#245strict=True(默认值)时,裁剪的边界框必须完全在页面的边界框内。
.within_bbox(bounding_box, relative=False, strict=True) 类似于.crop,但只保留完全在边界框内的对象。
.outside_bbox(bounding_box, relative=False, strict=True) 类似于.crop.within_bbox,但只保留完全在边界框外的对象。
.filter(test_function) 返回页面的一个版本,其中只有.objects``test_function(obj)返回True

…并且还具有以下方法:

方法 描述
.close() 默认情况下,Page对象缓存其布局和对象信息,以避免重新处理它。
然而,在解析大型PDF时,这些缓存的属性可能需要大量内存。
您可以使用此方法刷新缓存并释放内存。

以下各节介绍了其他方法:


5、对象

每个pdfplumber.PDFpdfplumber.Page实例 都提供对多种类型的PDF对象的访问,所有这些对象都派生自pdfminer.sixPDF解析。

以下属性分别返回匹配对象的Python列表:

  • .chars,每个代表一个文本字符。
  • .lines,每个表示一条一维线。
  • .rects,每个表示一个二维矩形。
  • .curves,每个代表pdfminer.six无法识别为线或矩形的任何一系列连接点。
  • .images,每个代表一个图像。
  • .annots,每个代表一个PDF注释(详细信息参见官方PDF规范的第8.4节)
  • .hyperlinks,每个表示子类型Link的单个PDF注释,并具有URI操作属性

每个对象都表示为一个简单的Pythondict,具有以下属性:

char特性
属性 描述
page_number 找到此字符的页码。
text 例如,zZ 或 “”。
fontname 字符字体的名称。
size 字体大小。
adv 等于文本宽度字体大小缩放系数。
upright 字符是否直立。
height 字符的高度。
width 字符的宽度。
x0 字符左侧到页面左侧的距离。
x1 字符右侧到页面左侧的距离。
y0 字符底部到页面底部的距离。
y1 字符顶部到页面底部的距离。
top 字符顶部到页面顶部的距离。
bottom 字符底部到页面顶部的距离页面。
doctop 字符顶部与文档顶部的距离。
matrix 此字符的“当前转换矩阵”。(详见下文。)
mcid 此字符的标记内容部分ID(如果有)(否则None)。实验属性。
tag 此字符的标记内容部分标签(如果有)(否则None)。实验属性。
ncs TKTK
stroking_pattern TKTK
non_stroking_pattern TKTK
stroking_color 字符轮廓(即笔画)的颜色。详见docs/colors.md
non_stroking_color 字符的内部颜色。详见docs/colors.md
object_type “char”

注意:字符的matrix属性表示“当前转换矩阵”,如PDF参考(第6版)第4.2.2节所述。

矩阵控制字符的缩放、倾斜和位置平移。旋转是缩放和倾斜的组合,但在大多数情况下可以认为等于x轴倾斜。

pdfplumber.ctm子模块定义了一个类CTM,它有助于这些计算。例如:

from pdfplumber.ctm import CTM
my_char = pdf.pages[0].chars[3]
my_char_ctm = CTM(*my_char["matrix"])
my_char_rotation = my_char_ctm.skew_x

line属性
属性 描述
page_number 找到此行的页码。
height 行的高度。
width 行的宽度。
x0 左端距页面左侧的距离。
x1 右端距页面左侧的距离。
y0 下端距页面底部的距离。
y1 上端距页面底部的距离。
top 行顶距页面顶部的距离。
bottom 行底距页面顶部的距离。
doctop 行顶距文档顶部的距离。
linewidth 线条的厚度。
stroking_color 线条的颜色。详见docs/colors.md
non_stroking_color 为线条路径指定的非描边颜色。详见docs/colors.md
mcid 此行的标记内容部分ID(如果有)(否则None)。实验属性。
tag 此行的标记内容部分标记(如果有)(否则为None)。实验属性。
object_type “line”

rect属性
属性 描述
page_number 找到此矩形的页码。
height 矩形的高度。
width 矩形的宽度。
x0 矩形左侧到页面左侧的距离。
x1 矩形右侧到页面左侧的距离。
y0 矩形底部到页面底部的距离。
y1 矩形顶部到页面底部的距离。
top 矩形顶部到页面顶部的距离。
bottom 矩形底部到页面顶部的距离。
doctop 矩形顶部到文档顶部的距离。
linewidth 线粗细。
stroking_color 矩形轮廓的颜色。详见docs/colors.md
non_stroking_color 矩形的填充颜色。详见docs/colors.md.
mcid 此rect的标记内容部分ID(如果有)(否则None)。实验属性.
tag 此rect的标记内容部分标记(如果有)(否则None)。实验属性。
object_type “rect”

curve 属性
属性 描述
page_number 找到此曲线的页码。
pts 一个(x, top)元组列表,表示曲线上的点
path 一个(cmd, *(x, top))元组列表描述完整的路径描述,包括(例如)贝塞尔曲线中使用的控制点。
height 曲线边界框的高度。
width 曲线边界框的宽度。
x0 曲线最左边点到页面左侧的距离。
x1 曲线最右边点到页面左侧的距离。
y0 曲线最低点到页面底部的距离。
y1 曲线最高点到页面底部的距离。
top 曲线最高点到页面顶部的距离。
bottom 距离
doctop 曲线最高点与文档顶部的距离。
linewidth 线的厚度。
fill 曲线路径定义的形状是否被填充。
stroking_color 曲线轮廓的颜色。详见docs/colors.md
non_stroking_color 曲线的填充颜色。详见docs/colors.md
dash A([dash_array], dash_phase)描述曲线破折号样式的元组。详见PDF规范的表4.6
mcid 此曲线的标记内容节ID(否则None)。实验属性。
tag 此曲线的标记内容节标签(否则None<–atag–20/>)。实验属性。
object_type “曲线”

派生属性

此外,pdfplumber.PDFpdfplumber.Page都提供了 对多个派生对象列表的访问:.rect_edges(将每个矩形分解为四行),.curve_edges(对curve对象做同样的事情)和.edges(结合了.rect_edges.curve_edges.lines)。


image属性

注意:虽然image对象的定位和特征可以通过pdfplumber获得,但此库不提供对重建图像内容的直接支持。为此,请参阅此建议

属性 描述
page_number 找到图像的页码。
height 图像的高度。
width 图像的宽度。
x0 图像左侧到页面左侧的距离。
x1 图像右侧到页面左侧的距离。
y0 图像底部到页面底部的距离。
y1 图像顶部到页面底部的距离。
top 图像顶部到页面顶部的距离。
bottom 图像底部到页面顶部的距离。
doctop 矩形顶部到文档顶部的距离。
srcsize 图像原始尺寸,作为(width, height)元组。
colorspace 图像的颜色域(例如,RGB)。
bits
stream 图像的像素值,作为pdfminer.pdftypes.PDFStream对象。
imagemask 一个可为空的布尔值;如果True,“指定图像数据将用作以当前颜色绘制的模板蒙版。”
mcid 此图像的标记内容部分ID(如果有)(否则None)。实验属性。
tag 此图像的标记内容部分标签(如果有)(否则None)。实验属性。
object_type “图像”

6、通过pdfminer获取更高级别的pdfminer.six

如果您将pdfminer.six-处理laparams参数传递给pdfplumber.open(...),那么每个页面的.objects字典也将包含pdfminer.six的高级布局对象,例如"textboxhorizontal"


四、可视化调试

pdfplumber的可视化调试工具有助于理解PDF的结构和从中提取的对象。


1、创建一个PageImage.to_image()

要将任何页面(包括裁剪的页面)转换为PageImage对象,请调用my_page.to_image()。您可以选择传递以下关键字参数之一

  • resolution:每英寸所需的像素数。默认值:72。类型:int
  • width:所需的图像宽度(以像素为单位)。默认值:未设置,由resolution决定。类型:int
  • height:所需的图像宽度,以像素为单位。默认值:未设置,由resolution决定。类型:int
  • antialias:创建图像时是否使用抗锯齿。设置为True会创建具有较少锯齿状文本和图形但具有较大文件大小的图像。默认值:False。类型:bool
  • force_mediabox:使用页面的.mediabox维度,而不是.cropbox维度。默认值:False。类型:bool

例如:

im = my_pdf.pages[0].to_image(resolution=150)

在脚本或REPL中,im.show()将在本地图像查看器中打开图像。但是PageImage对象也可以很好地与Jupyter笔记本配合使用;它们会自动呈现为单元格输出。例如:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意.to_image(...)按预期工作与Page.crop(...)/CroppedPage实例,但无法合并通过Page.filter(...)/FilteredPage实例所做的更改。


2、基本PageImage方法

方法 描述
im.reset() 清除到目前为止绘制的任何内容。
im.copy() 将图像复制到一个新的PageImage对象。
im.show() 在本地图像查看器中打开图像。
im.save(path_or_fileobject, format="PNG", quantize=True, colors=256, bits=8) 将带注释的图像保存为PNG文件。默认参数将图像量化为256种颜色的调色板,保存具有8位颜色深度的PNG。您可以通过传递quantize=False或通过传递colors=N来调整调色板的大小。

3、绘图方法

您可以将显式坐标或任何pdfplumberPDF对象(例如char、line、rect)传递给这些方法。

单对象方法 批量方法 描述
im.draw_line(line, stroke={color}, stroke_width=1) im.draw_lines(list_of_lines, **kwargs) linecurve或2元组的2元组(例如,((x, y), (x, y)))中绘制一条线。
im.draw_vline(location, stroke={color}, stroke_width=1) im.draw_vlines(list_of_locations, **kwargs) location.
im.draw_hline(location, stroke={color}, stroke_width=1) im.draw_hlines(list_of_locations, **kwargs) location指示的y坐标处绘制一条水平线。
im.draw_rect(bbox_or_obj, fill={color}, stroke={color}, stroke_width=1) im.draw_rects(list_of_rects, **kwargs) rect``char
im.draw_circle(center_or_obj, radius=5, fill={color}, stroke={color}) im.draw_circles(list_of_circles, **kwargs) (x, y)坐标或charrect等的中心绘制一个圆。

注意:上面的方法建立在Pillow的ImageDraw方法上,但是参数已经过调整,以与SVG的fill/stroke/stroke_width术语保持一致。


4、可视化调试表查找器

im.debug_tablefinder(table_settings={})将返回PageImage的一个版本,其中覆盖了检测到的线(红色)、交叉点(圆圈)和表格(浅蓝色)。


五、提取文本

pdfplumber可以从任何给定页面(包括裁剪和派生页面)中提取文本。它还可以尝试保留该文本的布局,以及识别单词和搜索查询的坐标。Page对象可以调用以下文本提取方法:


1、.extract_text(x_tolerance=3, x_tolerance_ratio=None, y_tolerance=3, layout=False, x_density=7.25, y_density=13, line_dir_render=None, char_dir_render=None, **kwargs)

将页面的所有字符对象整理成一个字符串。

  • layout=False时:添加一个字符的x1和下一个字符的x0之间的差异大于x_tolerance
    (如果x_tolerance_ratio不是None,则提取器使用动态x_tolerance等于x_tolerance_ratio * previous_character["size"]。)
    添加换行符,其中一个字符的doctop和下一个字符的doctop之间的差异大于y_tolerance
  • layout=True实验特征):尝试模仿页面上文本的结构布局,使用x_densityy_density确定每个“点”的最小字符/换行符数,PDF测量单位。
    传递line_dir_render="ttb"/"btt"/"ltr"/"rtl"和/或char_dir_render="ttb"/"btt"/"ltr"/"rtl"将以与默认不同的方向输出行/字符。
    所有剩余的**kwargs被传递到.extract_words(...)(见下文),计算布局的第一步。

2、.extract_text_simple(x_tolerance=3, y_tolerance=3)

稍快但不太灵活的版本.extract_text(...),使用更简单的逻辑。


3、.extract_words(x_tolerance=3, x_tolerance_ratio=None, y_tolerance=3, keep_blank_chars=False, use_text_flow=False, line_dir="ttb", char_dir="ltr", line_dir_rotated="ttb", char_dir_rotated="ltr", extra_attrs=[], split_at_punctuation=False, expand_ligatures=True, return_chars=False)

返回所有看起来像单词的东西及其边界框的列表。
单词被认为是字符序列,其中(对于“直立”字符)的x1和下一个字符的x0之间的差异小于或等于x_tolerance 其中一个字符的doctop和下一个字符的doctop小于或等于y_tolerance.(如果x_tolerance_ratio不是None,提取器使用动态x_tolerance等于x_tolerance_ratio * previous_character["size"].)非直立字符也采用了类似的方法,但测量它们之间的垂直距离,而不是水平距离。
keep_blank_chars更改为True将意味着空白字符被视为单词的一部分,而不是单词之间的空格。
use_text_flow更改为True将使用PDF的基础字符流作为单词排序和分割的指南,而不是按x/y位置预先排序字符。
(这模仿了拖动光标如何突出显示PDF中的文本;因此,顺序似乎并不总是合乎逻辑的。)line_dirchar_dir参数告诉此方法预期读取行/字符的方向;有效选项是“ttb”(从上到下)、“btt”(从下到上)、“ltr”(从左到右)和“rtl”(从右到左)。
line_dir_rotatedchar_dir_rotated参数相似,但用于已旋转的文本。
传递extra_attrs(例如,["fontname", "size"]将每个单词限制为与每个属性共享完全相同值的字符,生成的单词字典将指示这些属性。
split_at_punctuation设置为True将在以下指定的标点符号处强制执行中断标记string.punctuation;或者您可以通过传递字符串来指定分隔标点符号的列表,例如,split_at_punctuation='!"&'()*+,.:;<=>?@[]^{|}~'。 除非您设置expand_ligatures=False,否则连字符如将扩展为它们的组成字母(例如,fi)。 传递return_chars=True将向每个单词字典添加其组成字符的列表,作为"chars"`字段中的列表。


4、.extract_text_lines(layout=False, strip=True, return_chars=True, **kwargs)

实验功能,返回表示页面上文本行的字典列表。
strip参数的工作方式类似于Python的str.strip()方法,并返回没有周围空格的text属性。
(仅在layout = True时相关。)将return_chars设置为False将从返回的文本行字典中排除单个字符对象。
其余的**kwargs是您将传递给.extract_text(layout=True, ...)


5、.search(pattern, regex=True, case=True, main_group=0, return_groups=True, return_chars=True, layout=False, **kwargs)

实验功能,允许您搜索页面的文本,返回与查询匹配的所有实例的列表。
对于每个实例,响应字典对象包含匹配的文本、任何正则表达式组匹配、边界框坐标和char对象本身。
pattern可以是编译的正则表达式、未编译的正则表达式或非正则表达式字符串。
如果regexFalse,则该模式被视为非正则表达式字符串。
如果caseFalse,则以不区分大小写的方式执行搜索。
设置main_group将结果限制为pattern内的特定正则表达式组(默认值为0表示整个匹配)。
return_groups和/或return_chars设置为False将排除添加匹配的正则表达式组和/或字符的列表(作为"groups""chars"到返回字典)。
layout参数的操作方式与.extract_text(...)一样。
其余的**kwargs是您将传递给的.extract_text(layout=True, ...)
注意:零宽度和全空白匹配被丢弃,因为它们(通常)在页面上没有明确的位置。


6、.dedupe_chars(tolerance=1, extra_attrs=("fontname", "size"))

返回具有重复字符的页面版本-那些共享相同文本、定位(在tolerancex/y内)和与其他字符相同的字符-已删除。
(请参阅extra_attrs问题#71以了解动机。) |


六、提取表

pdfplumber的表格检测方法大量借鉴了Anssi Urminen的硕士论文,并受到Tabula的启发。它的工作原理是这样的:

  1. 对于任何给定的PDF页面,找到(a)明确定义和/或(b)由页面上的单词对齐暗示的行。
  2. 合并重叠或几乎重叠的线。
  3. 找出所有这些线的交点。
  4. 找到使用这些交点作为顶点的最粒度的矩形集(即单元格)。
  5. 将连续的单元格分组到表格中。

1、表提取方法

pdfplumber.Page对象可以调用以下表方法:

方法 描述
.find_tables(table_settings={}) 返回Table对象的列表。Table对象提供对.cells.rows.columns.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属性。

例如:

pdf = pdfplumber.open("path/to/my.pdf")
page = pdf.pages[0]
page.extract_table()

单击此处查看更详细的示例。


2、表提取设置

默认情况下,extract_tables使用页面的垂直线和水平线(或矩形边缘)作为单元格分隔符。但是该方法可以通过table_settings参数进行高度自定义。可能的设置及其默认值:

{
    "vertical_strategy": "lines", 
    "horizontal_strategy": "lines",
    "explicit_vertical_lines": [],
    "explicit_horizontal_lines": [],
    "snap_tolerance": 3,
    "snap_x_tolerance": 3,
    "snap_y_tolerance": 3,
    "join_tolerance": 3,
    "join_x_tolerance": 3,
    "join_y_tolerance": 3,
    "edge_min_length": 3,
    "min_words_vertical": 3,
    "min_words_horizontal": 1,
    "intersection_tolerance": 3,
    "intersection_x_tolerance": 3,
    "intersection_y_tolerance": 3,
    "text_tolerance": 3,
    "text_x_tolerance": 3,
    "text_y_tolerance": 3,
    "text_*":, # See below
}

设置 描述
"vertical_strategy" 要么是"lines""lines_strict""text"、或"explicit"。见下文解释。
"horizontal_strategy" 要么是"lines""lines_strict""text"、或"explicit"见下文解释。
"explicit_vertical_lines" 明确划分表格中单元格的垂直线列表。可以与上述任何策略结合使用。列表中的项目应该是数字——指示线条的x坐标(页面的全部高度)——或者line/rect/curve对象。
"explicit_horizontal_lines" 明确划分表格中单元格的水平线列表。可以与上述任何策略结合使用。列表中的项目应该是数字——表示一条线的y坐标(页面的全部高度)——或者line/rect/curve对象。
"snap_tolerance"
"snap_x_tolerance"
"snap_y_tolerance"
snap_tolerance点内的平行线将被“折断”到相同的水平或垂直位置。
"join_tolerance"
"join_x_tolerance"
"join_y_tolerance"
同一无穷线上的线段,其末端在彼此join_tolerance内,将被“连接”成一个线段。
"edge_min_length" 短于edge_min_length的边将在尝试重建表格之前被丢弃。
"min_words_vertical" 当使用"vertical_strategy": "text"时,至少min_words_vertical单词必须共享相同的对齐方式.
"min_words_horizontal" 使用"horizontal_strategy": "text"时,至少min_words_horizontal个词必须共享相同的对齐方式。
"intersection_tolerance"
"intersection_x_tolerance"
"intersection_y_tolerance"
当将边组合成单元格时,正交边必须在intersection_tolerance内才能被认为是相交的点。
"text_*" 然后在从每个发现的表中提取文本时使用以text_为前缀的所有设置。Page.extract_text(...)的所有可能参数在这里也有效。
"text_x_tolerance""text_y_tolerance" 这些text_-前缀设置适用于使用text策略时的table-identification算法。即,当该算法搜索单词时,它会期望每个单词中的单个字母相距不超过text_x_tolerance/text_y_tolerance点。

3、表提取策略

两个vertical_strategyhorizontal_strategy都接受以下选项:

策略 描述
"lines" 使用页面的图形线条——包括矩形对象的边——作为潜在表格单元格的边框。
"lines_strict" 使用页面的图形线条——但不包括矩形对象的边——作为潜在表格单元格的边框。
"text" 对于vertical_strategy:推导连接页面左、右或中心单词的(想象的)线条,并使用这些线条作为潜在表格单元格的边框。对于horizontal_strategy,相同但使用单词顶部。
"explicit" 仅使用explicit_vertical_lines/explicit_horizontal_lines.

4、笔记

  • 在尝试提取表之前,裁剪一个页面Page.crop(bounding_box)通常很有帮助。
  • 表提取pdfplumber从根本上重新设计v0.5.0,并引入了突破性的变化。

七、提取表单值

有时,PDF文件可以包含包含人们可以填写和保存的输入的表单。虽然表单字段中的值看起来像PDF文件中的其他文本,但表单数据的处理方式不同。如果您想要血淋淋的详细信息,请参阅本规范的第671页。

pdfplumber没有处理表单数据的接口,但您可以使用pdfplumberpdfminer包装器访问它。

例如,此片段将检索表单字段名称和值并将它们存储在字典中。

import pdfplumber
from pdfplumber.utils.pdfinternals import resolve_and_decode, resolve

pdf = pdfplumber.open("document_with_form.pdf")

def parse_field_helper(form_data, field, prefix=None):
    """ appends any PDF AcroForm field/value pairs in `field` to provided `form_data` list

        if `field` has child fields, those will be parsed recursively.
    """
    resolved_field = field.resolve()
    field_name = '.'.join(filter(lambda x: x, [prefix, resolve_and_decode(resolved_field.get("T"))]))
    if "Kids" in resolved_field:
        for kid_field in resolved_field["Kids"]:
            parse_field_helper(form_data, kid_field, prefix=field_name)
    if "T" in resolved_field or "TU" in resolved_field:
        # "T" is a field-name, but it's sometimes absent.
        # "TU" is the "alternate field name" and is often more human-readable
        # your PDF may have one, the other, or both.
        alternate_field_name  = resolve_and_decode(resolved_field.get("TU")) if resolved_field.get("TU") else None
        field_value = resolve_and_decode(resolved_field["V"]) if 'V' in resolved_field else None
        form_data.append([field_name, alternate_field_name, field_value])

form_data = []
fields = resolve(resolve(pdf.doc.catalog["AcroForm"])["Fields"])
for field in fields:
    parse_field_helper(form_data, field)

运行此脚本后,form_data一个列表,其中包含每个表单元素的三元素元组。例如,带有城市和州字段的PDF表单可能如下所示。

[
 ['STATE.0', 'enter STATE', 'CA'],
 ['section 2  accident infoRmation.1.0',
  'enter city of accident',
  'SAN FRANCISCO']
]

感谢@jeremybmerrill帮助维护上面的表单解析代码。


八、演示


九、与其他库的比较

其他几个Python库帮助用户从PDF中提取信息。作为一个广泛的概述,pdfplumber通过结合以下特性将自己与其他PDF处理库区分开来:

  • 轻松访问有关每个PDF对象的详细信息
  • 用于提取文本和表格的高级、可定制的方法
  • 紧密集成的可视化调试
  • 其他有用的实用功能,例如通过裁剪框过滤对象

了解pdfplumber提供哪些功能也很有帮助:

  • PDF生成
  • PDF修改
  • 光学字符识别(OCR)
  • 强大的支持从OCR文档中提取表格

具体比较

  • pdfminer.six提供了pdfplumber的基础,主要关注解析PDF,分析PDF布局和对象定位,提取文本,不提供表格提取或可视化调试的工具。
  • PyPDF2是一个纯Python库“能够拆分、合并、裁剪和转换PDF文件的页面。它还可以为PDF文件添加自定义数据、查看选项和密码。”它可以提取页面文本,但不提供对形状对象(矩形、线条等)、表格提取或可视化调试工具的轻松访问。
  • pymupdf大大快于pdfminer.six(因此也pdfplumber),可以生成和修改PDF,但该库需要安装非Python软件(MuPDF)。它也不允许轻松访问形状对象(矩形、线条等),并且不提供表格提取或可视化调试工具。
  • camelottabula-pypdftables都主要关注提取表。在某些情况下,它们可能更适合您尝试提取的特定表。

2024-08-22(四)
一周过得好快