一、关于 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等等。默认为所有可用。
--laparamsJSON格式的字符串( 例如,'{"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)。实验属性。
ncsTKTK
stroking_patternTKTK
non_stroking_patternTKTK
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
dashA([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(四)
一周过得好快

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部