给知⽹没有书签的pdf⽂件添加书签(利⽤python解析txt⽂件内容并为pdf添加⽬
录)
今天利⽤tampermonkey的脚本下载pdf格式论⽂时,发现论⽂缺少书签,⽽脚本可以下载⼀个txt格式的书签(⽬录),因此打算利⽤python将txt格式的⽬录添加到pdf中。
txt⽂件解析
txt ⽂件的读取
利⽤python读取txt⽂件时,使⽤的是python中的open⽅法,读取⽂件时最好加上⽂件的编码⽅式。不然有可能出现以下错误:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 14: illegal multibyte sequence
这是因为再windows系统中python读取⽂件时的默认编码⽅式不是utf-8导致的。
实现代码如下:
txtpath ="D:/⽬录.txt"
with open(txtpath,'r',encoding='utf-8')as f:
list_data = f.read()
print(type(list_data))# 打印⽂件读取得到变量的类型,输出结果为“str”,即⽂本类型
print(list_data)
转义字符的原样打印
通过以上步骤已经可以读取到txt⽂件中的内容了,由于换⾏符、制表符在使⽤print输出时会可视化输出,⽽不是输出\t \n 这种转移字符,⽽在进⾏⽂本内容解析时需要对这些转义字符进⾏解析,所以现在需要将转义字符原样输出,其⽅法是将字符串放到数组中,然后打印数组。
实现代码如下:
str='致谢\t5\n摘要\t6\nABSTRACT\t8\n1 绪论\t16\n\t1.1 研究意义\t16\n\t'
print([str])
输出结果:
['致谢\t5\n摘要\t6\nABSTRACT\t8\n1 绪论\t16\n\t1.1 研究意义\t16\n\t']
txt⽂件按⾏读取
⽽通过分析txt中的⽂本可以发现,txt⽂件中的内容每⾏对应⼀条⽬录,因此可以采⽤按⾏读取的⽅式⼀⾏⾏的去对⽂本进⾏解析。
按⾏读取的代码如下:
with open(txtpath,'r',encoding='utf-8')as f:
for line in f:
print([line])# 将⾏⽂本放在数组中打印是为了查看转移字符
pass
书签⽂本信息解析
观察每⾏⽂本信息可以发现,书签的格式⼤致为
\t书签⽂字\t页码\n
因此解析⽂本时,可以先到倒数第⼀个\t制表符,从⽽确定页码,然后就可以将页码以外的⽂本全部放到书签⽂本中了,⽽书签是⼏级书签,可以通过每⾏⽂字前⾯\t制表符的个数确定。
参考代码:
place('\n','')#去除\n
i0=line.rfind('\t')#在find前加r的效果是从后往前搜索
page_num=int(line[i0+1:])
line=line[:i0]
i0=0
page_grade=0
while(line.find('\t',i0,-1)!=-1):
page_grade+=1
i0 = line.find('\t',i0+1,-1)#更新i0,继续搜索
page_place('\t','')
需要注意的是,在查倒数第⼀个\t的时候,使⽤的事rfind函数,⽽不是find函数,这两个函数的区别是,rfind函数从后往前,find函数从前往后。
为pdf⽂件添加书签
这⾥需要⽤到的是PyPDF2库,⼤概流程是⽤reader读取pdf,将reader读取到的pdf复制到writer中,然后给writer中的pdf添加标签,最后保存pdf即可。
实现的代码如下:
from PyPDF2 import PdfFileReader as reader,PdfFileWriter as writer
pdfpath ="D:/1.pdf"
pdf_in = reader(pdfpath)
pdf_out = writer()
# 将读取的pdf放到writer中
pageCount = NumPages()
for iPage in range(pageCount):
pdf_out.addPage(Page(iPage))
parent0=pdf_out.addBookmark('⽗⽬录',0,parent =None)# 添加⽗⽬录
# 使⽤⽅法: addBookmark(书签⽂字,书签页码,书签的⽗⽬录),返回值是书签(可以作为其他书签的⽗⽬录)
parent1=pdf_out.addBookmark('⼦⽬录',0,parent = parent0)# 给⽗添加⼦⽬录
# 保存pdf
tampermonkeywith open('D:/1-bookmark.pdf','wb')as fout:
pdf_out.write(fout)
在复制pdf时没有使⽤cloneDocumentFromReader()⽅法,因为实际使⽤时发现使⽤了这个⽅法会在添加书签时报错,所以使⽤了⼀个折衷的⽅式,单页pdf复制。
ValueError: {'/Type': '/Outlines'} is not in list
为了让书签正确的添加到其⽗⽬录底下,程序在设计时引⽤了⼀个parent列表,实现⽅法如下:
curren_grade=0
parent.append(None)
with open(txtpath,'r',encoding='utf-8')as f:
for line in f:
place('\n','')#去除\n
i0=line.rfind('\t')#在find前加r的效果是从后往前搜索
page_num=int(line[i0+1:])
line=line[:i0]
i0=0
page_grade=0
while(line.find('\t',i0,-1)!=-1):
page_grade+=1
i0 = line.find('\t',i0+1,-1)#更新i0,继续搜索
page_place('\t','')
# 动态调整parent列表的长度
if curren_grade<page_grade:
parent.append(None)
curren_grade=page_grade
if page_grade==0:
parent[0]=pdf_out.addBookmark(page_text,page_num-1,parent =None)
else:
parent[page_grade]=pdf_out.addBookmark(page_text,page_num-1,parent = parent[page_grade-1])
同时引⽤了⼀个curren_grade变量,让程序中的parent列表长度可以根据⽬录总的等级数量动态的调整。
完整代码
以下是程序的完整代码,程序中txtpath为书签⽂件的输⼊路径,pdfpath为pdf路径,添加书签后的pdf输出路径为源⽬录下pdf⽂件⽂件名后添加**_bm**。
⽐如输⼊pdf路径为D:/1.pdf时,输出的路径就是D:/1_bm.pdf
import numpy as np
from PyPDF2 import PdfFileReader as reader,PdfFileWriter as writer
import os
def add_bookmarks(txtpath,pdfpath):
pdf_in = reader(pdfpath)
pdf_out = writer()
# pdf_out.cloneDocumentFromReader(pdf_in,after_page_append=None)
parent=[]
pageCount = NumPages()
for iPage in range(pageCount):
pdf_out.addPage(Page(iPage))
curren_grade=0
parent.append(None)
with open(txtpath,'r',encoding='utf-8')as f:
for line in f:
place('\n','')#去除\n
i0=line.rfind('\t')#在find前加r的效果是从后往前搜索
page_num=int(line[i0+1:])
line=line[:i0]
i0=0
page_grade=0
while(line.find('\t',i0,-1)!=-1):
page_grade+=1
i0 = line.find('\t',i0+1,-1)#更新i0,继续搜索
if curren_grade<page_grade:
parent.append(None)
curren_grade=page_grade
page_place('\t','')
if page_grade==0:
parent[0]=pdf_out.addBookmark(page_text,page_num-1,parent =None)
else:
parent[page_grade]=pdf_out.addBookmark(page_text,page_num-1,parent = parent[page_grade-1])
outpath = pdfpath[:-4]+'_bm.pdf'
with open(outpath,'wb')as fout:
pdf_out.write(fout)
if __name__ =='__main__':
txtpath ="D:/1_⽬录.txt"
pdfpath ="D:/1.pdf"
add_bookmarks(txtpath,pdfpath)
优化程序
接下来让程序⾃动的读取当前python脚本⽂件路径下的pdf⽂件和txt书签,然后匹配书签后再⾃动添加书签,避免⼿动输⼊路径的繁琐。(未完待续)
参考
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论