ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

利用Python在pdf文档中寻找某些词出现的页码

2019-07-27 16:01:36  阅读:1132  来源: 互联网

标签:文本 layout Python pdfminer pdf document 页码


要研究pdf文件的页码,首先要考虑这个文件的种类。pdf可能是一本书的电子版,可能是一份简历、可能是由Word、PPT或其他文档导出的……如果不是一本书,通常页面内容里是没有页码的;如果是一本书,虽然有页码,但是封面、前言、目录、章节的封面很可能不会标上页码,而正文的页码和该pdf文件本身的页码对不上,如页面里的第1页会是pdf的第5页,页面的第2页是pdf的第6页……为了统一,我将页码“定义”为pdf的文件的页码。

下面来试试如何通过Python找到词汇出现过的页码,首先我使用的是PyPDF2这个库,这个库使用起来非常简单,但是只能提取pdf中的文本信息,是可以用来寻找词汇的。我首先利用一篇英文文献试了一下:

 1 import PyPDF2
 2 
 3 pdf_File=open('C:\\Users\\user\\Desktop\\2016.pdf','rb')
 4 pdf_Obj=PyPDF2.PdfFileReader(pdf_File)
 5 pages=pdf_Obj.getNumPages()
 6 
 7 word_list=['predictedvalues','warfarin','NONMEM','atrialfibrillation','results']
 8 
 9 for w in word_list:
10     page_list=[]
11     for p in range(0,pages):
12         text=pdf_Obj.getPage(p).extractText()
13         if w in text:
14             page_list.append(p+1)
15     
16     print(w,page_list)

我要寻找的词汇是:predictive values, warfarin, NONMEM, atrial fibrillation, results,由于PyPDF2处理文本时,所有的空格都会消失,所以“predictive values”和“atrial fibrillation”写成了“predictivevalues”和“atrialfibrillation”。输出的结果如下:

可以发现,已经打印出了这些词汇出的页码。然而当我在一份中文pdf上再次应用时,却失败了。我首先想到是编码的问题,于是在第一行加上:

encoding=utf-8

去发现无济于事,那么会不会是这个库并不支持中文文本的提取呢?我在翻了一下这个项目的地址,发现早在2016年,已经有人发现了这个问题:

 

可惜的是这个问题到现在还是没有解决,所以PyPDF2这个库无法解决问题,只能另想办法了。

于是我尝试了另外一个库pdfminer,它比PyPDF2使用起来要复杂地多,不过相应地功能也更加强大,不仅可以提取文本,也可以提取图片、表格等,并且支持中文。但是这个库是为Python2打造的,万幸它有支持Python3的版本pdfminer.six,下面就开始干活吧。

首先导入要使用的模块:

1 from pdfminer.pdfparser import PDFParser,PDFDocument
2 from pdfminer.pdfinterp import PDFResourceManager,PDFPageInterpreter
3 from pdfminer.converter import PDFPageAggregator
4 from pdfminer.layout import LTTextBoxHorizontal,LAParams
5 from pdfminer.pdfinterp import PDFTextExtractionNotAllowed

在这一步我出错了好久,最后重启了IDE才顺利导入。

模块导入之后就是提取文本了。这一部分的代码我主要是借鉴了别人的,自己根据需求做了一些改动:

 1 def parsePDFtoTXT(pdf_path):
 2     fp = open(pdf_path, 'rb')
 3     # 创建一个pdf文档分析器
 4     parser = PDFParser(fp)  
 5     # 创建一个PDF文档对象存储文档结构
 6     document= PDFDocument()
 7     # 连接分析器与文档对象
 8     parser.set_document(document)
 9     document.set_parser(parser)
10     # 提供初始化密码
11     document.initialize()
12     # 检查文件是否允许文本提取
13     if not document.is_extractable:
14         raise PDFTextExtractionNotAllowed
15     else:
16         # 创建一个PDF资源管理器对象来存储共赏资源
17         rsrcmgr=PDFResourceManager()
18         # 设定参数进行分析
19         laparams=LAParams()
20         # 创建一个PDF设备对象
21         device=PDFPageAggregator(rsrcmgr,laparams=laparams)
22         # 创建一个PDF解释器对象
23         interpreter=PDFPageInterpreter(rsrcmgr,device)
24         # 处理每一页
25         for page in document.get_pages():
26             # 解析页面
27             interpreter.process_page(page)
28             # 接受该页面的LTPage对象
29             layout=device.get_result()
30             print(layout)
31             output=str(layout)
32             for x in layout:
33                 if (isinstance(x,LTTextBoxHorizontal)):
34                     text=x.get_text()
35                     output+=text
36             with open('C:\\Users\\user\\Desktop\\pdfoutput.txt','a',encoding='utf-8') as f:
37                 f.write(output)

这段代码功能的是提取目标pdf中的文本,将其保存为桌面的pdfoutout.txt这个文件。这一步对于提取文本来说没有问题,但是这样一来,所有关于页码的信息就荡然无存了。document.get_pages()是一个生成器(generator)对象,在解析页面时,对它进行遍历,从而一页一页地进行处理,解析的结果(包括文本、图片、表格等)存储在layout中,它是LTPage类型的对象,每一个页面都对应了一个layout。我们需要文本信息,就要判断其中的内容是否为横向文本框(LTTextBoxHorizontal),如果是,则获取其文本。不幸的是,我们虽然可以一页一页地解析页面,但是却无法一页一页输出解析的结果,换句话说,输出的txt文件失去了页面信息,无法用来获得词汇所出现的页面了。

我想到了一个解决办法。虽然无法逐页输出结果,但是我们可以逐页解析结果,那么在解析结果时,能否“留一手”,把页面信息也加上去呢?于是我加上第31行和第35行,在每页的结果前面加上“<LTPage(i) 0.000,0.000,595.200,841.800 rotate=0>”,i代表第i页,这样在所输出的文本里,就有了用于区分页码的依据。第30行的代码没有什么实际的作用,我写上去是为了充当进度条,每处理完一页就会打印一行,在pdf页数比较多时可以知道进行到哪一页了。

得到了带有页码信息的文本之后,就是查询目标词汇以及返回它所出现的页码了:

 1 def get_word_page(word_list):
 2     f=open('C:\\Users\\user\\Desktop\\pdfoutput.txt',encoding='utf-8')
 3     text_list=f.read().split('<LTPage')
 4     n=len(text_list)
 5     for w in word_list:
 6         page_list=[]
 7         for i in range(1,n):
 8             if w in text_list[i]:
 9                 page_list.append(i)
10         with open('C:\\Users\\user\\Desktop\\result.txt','a',encoding='utf-8') as f:
11                 f.write(w+str(page_list)+'\n')

我的处理方法是根据每页前的“<LTPage(i) 0.000,0.000,595.200,841.800 rotate=0>”把全部的文本进行切分,它们的每一部分都被作为元素存储于1个列表中。pdf有n页,列表中就会有n+1个元素(索引为0到n),其中第0个元素是我们不需要的,剩下的n个元素,其索引i就代表pdf的第i页。判断词汇是否存在于文本时,我用的是最简单的方法,这种方法无法区分大小,如“happy”、“Happy”、“HAPPY”,它们虽然大小写不一致,但实际上是同一个词,上述代码就无法通过“happy”找到后2个词,可以考虑利用正则表达式进行匹配来解决这个问题。最终的结果保存在桌面的result.txt文件中。

下面用一篇中文文献来试验一下,完整的代码如下:

# -*- coding: utf-8 -*-

from pdfminer.pdfparser import PDFParser,PDFDocument
from pdfminer.pdfinterp import PDFResourceManager,PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTTextBoxHorizontal,LAParams
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed

def parsePDFtoTXT(pdf_path):
    fp = open(pdf_path, 'rb')
    parser = PDFParser(fp)  
    document= PDFDocument()
    parser.set_document(document)
    document.set_parser(parser)
    document.initialize()
    if not document.is_extractable:
        raise PDFTextExtractionNotAllowed
    else:
        rsrcmgr=PDFResourceManager()
        laparams=LAParams()
        device=PDFPageAggregator(rsrcmgr,laparams=laparams)
        interpreter=PDFPageInterpreter(rsrcmgr,device)
        for page in document.get_pages():
            interpreter.process_page(page)
            layout=device.get_result()
            print(layout)
            output=str(layout)
            for x in layout:
                if (isinstance(x,LTTextBoxHorizontal)):
                    text=x.get_text()
                    output+=text
            with open('C:\\Users\\user\\Desktop\\pdfoutput.txt','a',encoding='utf-8') as f:
                f.write(output)

def get_word_page(word_list):
    f=open('C:\\Users\\user\\Desktop\\pdfoutput.txt',encoding='utf-8')
    text_list=f.read().split('<LTPage')
    n=len(text_list)
    for w in word_list:
        page_list=[]
        for i in range(1,n):
            if w in text_list[i]:
                page_list.append(i)
        with open('C:\\Users\\user\\Desktop\\result.txt','a',encoding='utf-8') as f:
                f.write(w+str(page_list)+'\n')
                
if __name__=='__main__':
    parsePDFtoTXT('C:\\Users\\user\\Desktop\\群体药动学原理建立卡马西平和丙戊酸的定时定量给药模型及临床应用_林玮玮.pdf')
    get_word_page(['群体药动学','服药时间','知情同意书','NONMEM','贝叶斯反馈'])

运行后生成的pdfoutput.txt的内容如下:

结果文件result.txt如下:

可以看到已经得到了目标词汇所出现过的页码。

标签:文本,layout,Python,pdfminer,pdf,document,页码
来源: https://www.cnblogs.com/zm-pop-pk/p/11255436.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有