目前我正在考虑使用pyPdf进行一些PDF合并,但有时输入的顺序不正确,所以我正在研究每页的页面编号,以确定它应该进入的顺序(例如,如果有人将一本书分成20页10页PDF,我想把它们重新组合在一起).
我有两个问题 - 1.)我知道有时页码存储在文档数据的某个地方,因为我看到在Adobe上呈现的PDF类似于[1243](10 of 150),但我读过这种文件到pyPDF我找不到任何表明页码的信息 - 这个存储在哪里?
2.)如果avenue#1不可用,我想我可以遍历给定页面上的对象以尝试查找页码 - 可能是它自己的对象中有一个数字.但是,我似乎无法找到任何明确的方法来确定对象的内容.如果我跑:
pdf.getPage(0).getContents()
Run Code Online (Sandbox Code Playgroud)
这通常会返回:
{'/Filter': '/FlateDecode'}
Run Code Online (Sandbox Code Playgroud)
或者它返回IndirectObject(num,num)对象的列表.我真的不知道如何处理其中任何一个,据我所知,它没有真正的文档.熟悉这种事情的人是否能指出我正确的方向?
Jos*_*osh 36
以下对我有用:
from PyPDF2 import PdfFileReader
pdf = PdfFileReader(open('path/to/file.pdf','rb'))
pdf.getNumPages()
Run Code Online (Sandbox Code Playgroud)
Bry*_*Kou 13
其他答案使用 PyPDF/PyPDF2,它似乎可以读取整个文件。对于大文件,这需要很长时间。
与此同时,我写了一些快速而肮脏的东西,运行时间不长。它执行了一个 shell 调用,但我不知道有任何其他方法可以做到这一点。它可以非常快速地获取大约 5000 页的 pdf 页数。
它只需调用“pdfinfo”shell 命令即可工作,因此它可能仅适用于 linux。到目前为止,我只在 ubuntu 上测试过它。
我见过的一个奇怪的行为是,在 try/except 块中围绕它不会捕获错误,您必须排除 subprocess.CalledProcessError。
from subprocess import check_output
def get_num_pages(pdf_path):
output = check_output(["pdfinfo", pdf_path]).decode()
pages_line = [line for line in output.splitlines() if "Pages:" in line][0]
num_pages = int(pages_line.split(":")[1])
return num_pages
Run Code Online (Sandbox Code Playgroud)
有关完整文档,请参阅Adobe的978页PDF参考.:-)
更具体地说,PDF文件包含指示PDF的物理页面如何映射到逻辑页码以及如何格式化页码的元数据.这是您获取规范结果的地方.此页面的示例2 显示了它在PDF标记中的外观.你必须把它解决,解析它,并自己执行映射.
在PyPDF中,要获取此信息,请尝试作为起点:
pdf.trailer["/Root"]["/PageLabels"]["/Nums"]
Run Code Online (Sandbox Code Playgroud)
顺便说一句,当您看到一个IndirectObject
实例时,可以调用其getObject()
方法来检索指向的实际对象.
正如您所说,您的选择是检查文本对象并尝试确定哪个是页码.您可以使用extractText()
页面对象,但是您将获得一个字符串,并且必须尝试从中删除页码.(当然,页码可能是罗马字母或字母而不是数字,有些页面可能没有编号.)相反,看看extractText()
它的工作实际上是如何用Python编写的,毕竟 - 并将其用作例程的基础,单独检查页面上的每个文本对象,看它是否像页码一样.警惕那些有很多页码的TOC /索引页面!
kindall的回答非常好。但是,由于后来(梦想家)要求提供工作代码示例,并且由于我今天遇到了同样的问题,因此我想添加一些注释。
pdf结构不统一;您可以依赖的东西很少,因此任何有效的代码示例都不太可能对每个人都有效。在这个答案中可以找到一个很好的解释。
正如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")
Run Code Online (Sandbox Code Playgroud)
脚本:
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)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
25854 次 |
最近记录: |