Python-PyPDF2库-根据标签获取页码

之前利用PyPDF2库完成过PDF的拆分、合并、页面重组的功能,主要利用了 PdfFileReader PdfFileWriter PdfFileMerger 。单纯论PDF页面级别的操作,PyPDF2库是比较灵活的,而且最近还发现PdfFileReader甚至可以读取PDF的标签内容。----环境Python3.8

正好当前有一个需求是 根据不同的一级标签,拆分PDF 。现有资料极少描述如何根据标签获取相应的页码,这里主要运用了 .getOutlines() .getDestinationPageNumber()

  1. 首先,利用 PdfFileReader 创建一个pdf对象,获取该pdf的标签的代码如下:
from PyPDF2 import PdfFileReader
pdf = PdfFileReader('PDF路径')
bookmarks = pdf.getOutlines()

返回值为代表所有标签对应类(PyPDF2库下的特定Destination类)的集合列表,顺序则按照pdf内的标签顺序排列,形如:

[{'/Title': 'Test 1', '/Page': IndirectObject(14997, 0), '/Type': '/FitH', '/Top': 846}, {'/Title': 'Test 2', '/Page': IndirectObject(7, 0), '/Type': '/FitH', '/Top': 846}, {'/Title': 'Test 3', '/Page': IndirectObject(18, 0), '/Type': '/FitH', '/Top': 846} ,......]

每个类均可以利用形如字典的方式提取该类的一些属性,其中'/Title': 'Test 1'中的'Test 1'即代表该标签下的内容。

2. 接着,对于列表里的每个Destination类,可以用如下方式获取每个标签的页码,再进行拆分(此节不展开描述):

page = [] #获得的标签页码的集合将被放入page列表
for i in range(len(bookmarks)):
    page.append([i['/Title'], pdf.getDestinationPageNumber(bookmarks[i])]) #这里放入了一个二维列表

3. 实际上,题目中的例子较为简单,PDF中所有标签均为一级标签。如果存在二级标签, .getOutlines() 将返回嵌套列表:

[{'/Title': 'Test 1', '/Page': IndirectObject(14997, 0), '/Type': '/FitH', '/Top': 846}, [{'/Title': 'Test 1-1', '/Page': IndirectObject(14998, 0), '/Type': '/XYZ', '/Left': -11, '/Top': 853, '/Zoom': <PyPDF2.generic.NullObject object at 0x0000017E1EF9E490>}, {'/Title': 'Test 1-2', '/Page': IndirectObject(1, 0), '/Type': '/XYZ', '/Left': -11, '/Top': 603, '/Zoom': <PyPDF2.generic.NullObject object at 0x0000017E1EF9E730>}], {'/Title': 'Test 2', '/Page': IndirectObject(7, 0), '/Type': '/FitH', '/Top': 846} ,......]

这时2中循环获取页码的方式可能出错,我们也可以再嵌套一个for循环。可是,如果存在更多级别的子级标签,而我们并不确定要加多少for循环。对于这类,可以用简单的递归方式实现。

page = []
def get_pagenum(page, lit):
    for i in range(len(lit):