使用pyPDF从文档中检索页码

2024-04-26 14:23:37 发布

您现在位置:Python中文网/ 问答频道 /正文

目前,我正在研究将PDF与pyPdf合并,但有时输入的顺序不对,所以我正在研究将每一页的页数都刮去,以确定它应该进入的顺序(例如,如果有人将一本书拆分成20个10页的PDF,我想将它们放回一起)。

我有两个问题-1)我知道有时候页码存储在文档数据中的某个地方,就像我在Adobe上看到的PDF呈现为类似[1243](10/150)的东西一样,但是我已经将这类文档读入pyPDF,我找不到任何指示页码的信息-它存储在哪里?

2.)如果avenue#1不可用,我想我可以遍历给定页面上的对象,试图找到一个页码-可能是它自己的对象,其中只有一个页码。但是,我似乎找不到任何明确的方法来确定对象的内容。如果我跑:

pdf.getPage(0).getContents()

这通常会返回:

{'/Filter': '/FlateDecode'}

或者返回间接对象(num,num)的列表。我真的不知道该怎么处理这两个问题,而且据我所知还没有真正的文档。有没有人知道这样的事情会给我指明正确的方向?


Tags: 数据对象文档信息pdf顺序地方页面
3条回答

以下对我有效:

from PyPDF2 import PdfFileReader
pdf = PdfFileReader(open('path/to/file.pdf','rb'))
pdf.getNumPages()

有关完整文档,请参见Adobe的978第PDF Reference页。:-)

更具体地说,PDF文件包含元数据,这些元数据指示PDF的物理页面如何映射到逻辑页码,以及页码应如何格式化。这就是你追求规范结果的地方。示例2of this page显示了在PDF标记中的外观。你必须找出它,解析它,然后自己进行映射。

在PyPDF中,要获取此信息,请尝试,作为起点:

pdf.trailer["/Root"]["/PageLabels"]["/Nums"]

顺便说一下,当您看到一个IndirectObject实例时,可以调用它的getObject()方法来检索被指向的实际对象。

您的替代方法是,正如您所说,检查文本对象并尝试找出哪个是页码。您可以使用页面对象的extractText()进行此操作,但是您将得到一个字符串,并且必须尝试从中找出页码。(当然,页码可能是罗马或字母,而不是数字,有些页面可能没有编号。)相反,看看extractText()实际上是如何使用Python编写PyPDF的,毕竟它是一个例程的基础,该例程分别检查页面上的每个文本对象,看看它是否像页码。当心那些上面有很多页码的目录/索引页!

答案很好。但是,由于稍后(dreamer)请求了一个工作代码示例,而且我今天也遇到了同样的问题,所以我想添加一些注释。

  1. pdf结构并不统一;您可以依赖的东西很少,因此任何工作代码示例都不太可能适合每个人。一个很好的解释可以找到in this answer

  2. 正如kindall所解释的,您很可能需要探索您正在处理的pdf文件。

就像这样:

import sys
import PyPDF2 as pyPdf

"""Open your pdf"""
pdf = pyPdf.PdfFileReader(open(sys.argv[1], "rb"))

"""Explore the /PageLabels (if it exists)"""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]
    print(page_label_type)
except:
    print("No /PageLabel object")

"""Select the item that is most likely to contain the information you desire; e.g.
       {'/Nums': [0, IndirectObject(42, 0)]}
   here, we only have "/Num". """

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"]
    print(page_label_type)
except:
    print("No /PageLabel object")

"""If you see a list, like
       [0, IndirectObject(42, 0)]
   get the correct item from it"""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1]
    print(page_label_type)
except:
    print("No /PageLabel object")

"""If you then have an indirect object, like
       IndirectObject(42, 0)
   use getObject()"""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()
    print(page_label_type)
except:
    print("No /PageLabel object")

"""Now we have e.g.
       {'/S': '/r', '/St': 21}
   meaning roman numerals, starting with page 21, i.e. xxi. We can now also obtain the two variables directly."""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/S"]
    print(page_label_type)
    start_page = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/St"]
    print(start_page)
except:
    print("No /PageLabel object")
  1. 从ISO pdf 1.7规范(相关章节here)中可以看到,如何标记页面有很多可能性。作为一个简单的工作示例,请考虑这个脚本,它将至少处理十进制(阿拉伯语)和罗马数字:

脚本:

import sys
import PyPDF2 as pyPdf

def arabic_to_roman(arabic):
    roman = ''
    while arabic >= 1000:
      roman += 'm'
      arabic -= 1000
    diffs = [900, 500, 400, 300, 200, 100, 90, 50, 40, 30, 20, 10, 9, 5, 4, 3, 2, 1]
    digits = ['cm', 'd', 'cd', 'ccc', 'cc', 'c', 'xc', 'l', 'xl', 'xxx', 'xx', 'x', 'ix', 'v', 'iv', 'iii', 'ii', 'i']
    for i in range(len(diffs)):
      if arabic >= diffs[i]:
        roman += digits[i]
        arabic -= diffs[i]
    return(roman)

def get_page_labels(pdf):
    try:
        page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/S"]
    except:
        page_label_type = "/D"
    try:
        page_start = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/St"]
    except:
        page_start = 1
    page_count = pdf.getNumPages()
    ##or, if you feel fancy, do:
    #page_count = pdf.trailer["/Root"]["/Pages"]["/Count"]
    page_stop = page_start + page_count 

    if page_label_type == "/D":
        page_numbers = list(range(page_start, page_stop))
        for i in range(len(page_numbers)):
            page_numbers[i] = str(page_numbers[i])
    elif page_label_type == '/r':
        page_numbers_arabic = range(page_start, page_stop)
        page_numbers = []
        for i in range(len(page_numbers_arabic)):
            page_numbers.append(arabic_to_roman(page_numbers_arabic[i]))

    print(page_label_type)
    print(page_start)
    print(page_count)
    print(page_numbers)

pdf = pyPdf.PdfFileReader(open(sys.argv[1], "rb"))
get_page_labels(pdf)

相关问题 更多 >