今天利用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制表符的个数确定。
参考代码:

for line in f:line=line.replace('\n','') #去除\ni0=line.rfind('\t') #在find前加r的效果是从后往前搜索page_num=int(line[i0+1:])line=line[:i0]i0=0page_grade=0while(line.find('\t',i0,-1)!=-1):page_grade+=1i0 = line.find('\t',i0+1,-1) #更新i0,继续搜索page_text=line.replace('\t','')

需要注意的是,在查找倒数第一个\t的时候,使用的事rfind函数,而不是find函数,这两个函数的区别是,rfind函数从后往前找,find函数从前往后找。

为pdf文件添加书签

这里需要用到的是PyPDF2库,大概流程是用reader读取pdf,将reader读取到的pdf复制到writer中,然后给writer中的pdf添加标签,最后保存pdf即可。
实现的代码如下:

from PyPDF2 import PdfFileReader as reader,PdfFileWriter as writerpdfpath = "D:/1.pdf"
pdf_in = reader(pdfpath)
pdf_out = writer()# 将读取的pdf放到writer中
pageCount = pdf_in.getNumPages()
for iPage in range(pageCount):pdf_out.addPage(pdf_in.getPage(iPage))parent0=pdf_out.addBookmark('父目录',0,parent = None) # 添加父目录
# 使用方法: addBookmark(书签文字,书签页码,书签的父目录),返回值是书签(可以作为其他书签的父目录)
parent1=pdf_out.addBookmark('子目录',0,parent = parent0) # 给父添加子目录# 保存pdf
with open('D:/1-bookmark.pdf','wb') as fout:pdf_out.write(fout)

在复制pdf时没有使用cloneDocumentFromReader()方法,因为实际使用时发现使用了这个方法会在添加书签时报错,所以使用了一个折衷的方式,单页pdf复制。

ValueError: {'/Type': '/Outlines'} is not in list

为了让书签正确的添加到其父目录底下,程序在设计时引用了一个parent列表,实现方法如下:

parent=[]
curren_grade=0
parent.append(None)
with open(txtpath,'r',encoding='utf-8') as f:for line in f:line=line.replace('\n','') #去除\ni0=line.rfind('\t') #在find前加r的效果是从后往前搜索page_num=int(line[i0+1:])line=line[:i0]i0=0page_grade=0while(line.find('\t',i0,-1)!=-1):page_grade+=1i0 = line.find('\t',i0+1,-1) #更新i0,继续搜索page_text=line.replace('\t','')# 动态调整parent列表的长度if curren_grade<page_grade:parent.append(None)curren_grade=page_gradeif 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 osdef add_bookmarks(txtpath,pdfpath):pdf_in = reader(pdfpath)pdf_out = writer()# pdf_out.cloneDocumentFromReader(pdf_in,after_page_append=None)parent=[]pageCount = pdf_in.getNumPages()for iPage in range(pageCount):pdf_out.addPage(pdf_in.getPage(iPage))curren_grade=0parent.append(None)with open(txtpath,'r',encoding='utf-8') as f:for line in f:line=line.replace('\n','') #去除\ni0=line.rfind('\t') #在find前加r的效果是从后往前搜索page_num=int(line[i0+1:])line=line[:i0]i0=0page_grade=0while(line.find('\t',i0,-1)!=-1):page_grade+=1i0 = line.find('\t',i0+1,-1) #更新i0,继续搜索if curren_grade<page_grade:parent.append(None)curren_grade=page_gradepage_text=line.replace('\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书签,然后匹配书签后再自动添加书签,避免手动输入路径的繁琐。
(未完待续)

参考

用Python为PDF文件批量添加书签 - 简书
用python合并pdf,并添加书签_BlowfishKing的博客-CSDN博客
python 反向查找_weixin_30596735的博客-CSDN博客
【python】读取和输出到txt_flora-CSDN博客
python遍历目录下所有文件 - 努力奋斗小青年 - 博客园

给知网没有书签的pdf文件添加书签(利用python解析txt文件内容并为pdf添加目录)相关推荐

  1. 24位ADC数据转换,保存为hex文件,并利用python解析hex文件画图

     目前有许多ADC芯片都是24位精度的,这个位数稍显尴尬,因为在常用的变量类型中,有8bit.16bit.32bit,唯独没有24bit,这就导致我们在很多情况下,需要自己敲代码去处理这个24bit的 ...

  2. 利用python保存txt文件的指定行/前n行

    ** 利用python保存txt文件的指定行/前n行-等 1.txt文件,每隔n行保存 originPath='open.txt' savePath='save.txt' # 每隔多少行保存一次 l= ...

  3. python生成多级文件夹_利用 python 遍历多级文件夹处理不同文件

    需求:近期,同事在处理文件的时候,常常需要从一堆文件中提取一些数据信息: 分析:由于每个文件夹下面的文件或文件夹多如牛毛,文件类型也很多种,需要针对不同文件类型做处理,人工处理是不现实的,只能用脚本处 ...

  4. 利用python将txt文件中的内容写入Excel文件中

    Python是一个强大的语言,解决这点问题非常简单. 首先我们先下载两个包,xlrd,xlwt分别可实现对excel文件的读和写操作. 接下来详见代码: 1.从txt里写入excel文件 # codi ...

  5. python读取文件并存入mysql_1.python读取txt文件并插入到mysql数据库以及将py脚本文件打包成独立的exe程序...

    读取txt文件并插入到mysql数据库 该小脚本适用于每天生成日志等信息到txt文本,然后通过windows的计划任务定时去执行python脚本打包成的exe文件,并将txt中内容读取以及格式化后插入 ...

  6. python 解析pb文件_利用Python解析json文件

    写在前面 在金融风控领域,我们经常会使用到json格式的数据,例如运营商数据.第三方数据等.而这些数据往往不能直接作为结构化数据进行分析和建模.本文将介绍一种简单的.可复用性高的基于pandas的方法 ...

  7. python 创建txt文件并写入字符串-python创建txt文件

    1.自己写入txt 直接上核心代码:with open("douban.txt","w") as f: f.write("这是个测试!")1 ...

  8. 利用Python合并txt文件

    import os path = "./执行第1次(1)" result = "merge_1.txt" #存放结果的文件 file = open(result ...

  9. python文件去重软件_Python实现的txt文件去重功能示例

    本文实例讲述了Python实现的txt文件去重功能.分享给大家供大家参考,具体如下: # -*- coding:utf-8 -*- #! python2 import shutil a=0 readD ...

最新文章

  1. Java除法不精确引入BigDecimal
  2. winsock 函数声明大全
  3. VTK:IO之ReadImageData
  4. lambda函数 RUNOOB python练习题49
  5. Django搜索工具——全文检索
  6. 深入体验php项目开发.pdf,《深入体验PHP项目开发》.(谭贞军).[PDF]
  7. mysql锁表语句,从理论到实践!
  8. PowerDesigner(四)-业务处理模型(转)
  9. PHP:CURL分别以GET、POST方式请求HTTPS协议接口api
  10. linux设置伪静态地址,wordpress网站linux和win主机URL伪静态设置方法详解
  11. beetl模板使用场景_Beetl模板引擎入门教程
  12. OpenGL纹理叠加
  13. 小众软件(持续更新)
  14. matlab中Ctphi什么意思,Matlab在物理上的应用举例
  15. “无法识别的USB设备”如何解决
  16. 星星之火-36:LTE载波载波的间隔是15K, 载波波的带宽是多少? 15K还是30K?
  17. 天宝水准仪DINI数据传输遇到问题
  18. 语义化的理解:有哪些语义化标签?有什么作用?
  19. 测试开发之Python核心笔记(7):输入与输出
  20. python 黑屏检测

热门文章

  1. 时序收敛以及 synplify 技巧timing constraint
  2. 变电站机器人监控系统界面(附源码)
  3. 嵌入式开发工具——嵌入式Qt连接mysql
  4. MLP多层感知器+BP算法原理及实战
  5. 系统升级/重装导致金蝶数据库账套丢失找回
  6. java毕业设计项目源代码S2SH基于JSP的网上购书系统|商城电商购物系统
  7. fxssvc.exe
  8. LaTex命令和环境的定义与重定义
  9. 移动创维E900V21C救砖过程,附线刷刷机固件
  10. eclipse maven插件问题:error occurred while automatically activating bundle org.eclipse.m2e.core.ui (525)