码迷,mamicode.com
首页 > 编程语言 > 详细

深入学习python解析并读取PDF文件内容的方法

时间:2018-08-06 21:09:07      阅读:283      评论:0      收藏:0      [点我收藏+]

标签:layout   __init__   RoCE   rds   app   const   tor   word   params   

  这篇文章主要学习了python解析并读取PDF文件内容的方法,包括对学习库的应用,python2.7和python3.6中python解析PDF文件内容库的更新,包括对pdfminer库的详细解释和应用。主要参考了一些已有的博客内容,代码。

  主要思路是首先利用一个做项目的形式,描述所做的问题,运行环境,和需要安装的库,然后写代码,此代码是在python2.7中运行,然后写出在python3.6中运行的代码,并详细解释python2.7和python3.6中python库的一些不同之处,最后详细的解释了代码的意思,和库的思路,最终的目的就让我们理解,并学会应用python解析并读取PDF文件内容的方法。

一,问题描述

  利用python读取PDF文本内容

二,运行环境

  python 3.6

三, 需要安装的库

pip install pdfminer

  

四,实现源代码(其中代码1和代码2都是python2.7实现的)

代码1(win64)

# coding=utf-8
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8‘)
import time
time1=time.time()
import os.path
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
result=[]
class CPdf2TxtManager():
  def __init__(self):
    ‘‘‘‘‘
    Constructor
    ‘‘‘
  def changePdfToText(self, filePath):
    file = open(path, ‘rb‘) # 以二进制读模式打开
    #用文件对象来创建一个pdf文档分析器
    praser = PDFParser(file)
    # 创建一个PDF文档
    doc = PDFDocument()
    # 连接分析器 与文档对象
    praser.set_document(doc)
    doc.set_parser(praser)
    # 提供初始化密码
    # 如果没有密码 就创建一个空的字符串
    doc.initialize()
    # 检测文档是否提供txt转换,不提供就忽略
    if not doc.is_extractable:
      raise PDFTextExtractionNotAllowed
    # 创建PDf 资源管理器 来管理共享资源
    rsrcmgr = PDFResourceManager()
    # 创建一个PDF设备对象
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    # 创建一个PDF解释器对象
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    pdfStr = ‘‘
    # 循环遍历列表,每次处理一个page的内容
    for page in doc.get_pages(): # doc.get_pages() 获取page列表
      interpreter.process_page(page)
      # 接受该页面的LTPage对象
      layout = device.get_result()
      for x in layout:
        if hasattr(x, "get_text"):
          # print x.get_text()
          result.append(x.get_text())
          fileNames = os.path.splitext(filePath)
          with open(fileNames[0] + ‘.txt‘,‘wb‘) as f:
            results = x.get_text()
            print(results)
            f.write(results + ‘\n‘)
if __name__ == ‘__main__‘:
  ‘‘‘‘‘
   解析pdf 文本,保存到txt文件中
  ‘‘‘
  path = u‘C:/data3.pdf‘
  pdf2TxtManager = CPdf2TxtManager()
  pdf2TxtManager.changePdfToText(path)
  # print result[0]
  time2 = time.time()
  print u‘ok,解析pdf结束!‘
  print u‘总共耗时:‘ + str(time2 - time1) + ‘s‘

  

代码2(win32)

# coding=utf-8
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8‘)
import time
time1=time.time()
import os.path
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFTextExtractionNotAllowed
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
result=[]
class CPdf2TxtManager():
  def __init__(self):
    ‘‘‘‘‘
    Constructor
    ‘‘‘
  def changePdfToText(self, filePath):
    file = open(path, ‘rb‘) # 以二进制读模式打开
    #用文件对象来创建一个pdf文档分析器
    praser = PDFParser(file)
    # 创建一个PDF文档
    doc = PDFDocument(praser)
    # 检测文档是否提供txt转换,不提供就忽略
    if not doc.is_extractable:
      raise PDFTextExtractionNotAllowed
    # 创建PDf 资源管理器 来管理共享资源
    rsrcmgr = PDFResourceManager()
    # 创建一个PDF设备对象
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    # 创建一个PDF解释器对象
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    pdfStr = ‘‘
    # 循环遍历列表,每次处理一个page的内容
    for page in PDFPage.create_pages(doc): # doc.get_pages() 获取page列表
      interpreter.process_page(page)
      # 接受该页面的LTPage对象
      layout = device.get_result()
      for x in layout:
        if hasattr(x, "get_text"):
          # print x.get_text()
          result.append(x.get_text())
          fileNames = os.path.splitext(filePath)
          with open(fileNames[0] + ‘.txt‘,‘wb‘) as f:
            results = x.get_text()
            print(results)
            f.write(results + ‘\n‘)
if __name__ == ‘__main__‘:
  ‘‘‘‘‘
   解析pdf 文本,保存到txt文件中
  ‘‘‘
  path = u‘C:/36.pdf‘
  pdf2TxtManager = CPdf2TxtManager()
  pdf2TxtManager.changePdfToText(path)
  # print result[0]
  time2 = time.time()
  print u‘ok,解析pdf结束!‘
  print u‘总共耗时:‘ + str(time2 - time1) + ‘s‘

  

五,python3.6中如何改进python2.7实现的代码

  问题一,reload的改进

import sys 
reload(sys) 
sys.setdefaultencoding(‘utf-8’) 

  以上是python2的写法,但是在python3中这个需要已经不存在了,这么做也不会什么实际意义。 

  在Python2.x中由于str和byte之间没有明显区别,经常要依赖于defaultencoding来做转换。 
  在python3中有了明确的str和byte类型区别,从一种类型转换成另一种类型要显式指定encoding。

  但是仍然可以使用这个方法代替 

import importlib,sys 
importlib.reload(sys)

  

  问题二,pdfminer模块的安装

  在python2.7中可以直接安装

pip install pdfminer

  在python3.6中就需要安装

pip install pdfminer3k

  

六   python3.6的源代码

import pyocr
import importlib
import sys
import time

importlib.reload(sys)
time1 = time.time()
# print("初始时间为:",time1)

import os.path
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

text_path = r‘words-words.pdf‘
# text_path = r‘photo-words.pdf‘

def parse():
    ‘‘‘解析PDF文本,并保存到TXT文件中‘‘‘
    fp = open(text_path,‘rb‘)
    #用文件对象创建一个PDF文档分析器
    parser = PDFParser(fp)
    #创建一个PDF文档
    doc = PDFDocument()
    #连接分析器,与文档对象
    parser.set_document(doc)
    doc.set_parser(parser)

    #提供初始化密码,如果没有密码,就创建一个空的字符串
    doc.initialize()

    #检测文档是否提供txt转换,不提供就忽略
    if not doc.is_extractable:
        raise PDFTextExtractionNotAllowed
    else:
        #创建PDF,资源管理器,来共享资源
        rsrcmgr = PDFResourceManager()
        #创建一个PDF设备对象
        laparams = LAParams()
        device = PDFPageAggregator(rsrcmgr,laparams=laparams)
        #创建一个PDF解释其对象
        interpreter = PDFPageInterpreter(rsrcmgr,device)

        #循环遍历列表,每次处理一个page内容
        # doc.get_pages() 获取page列表
        for page in doc.get_pages():
            interpreter.process_page(page)
            #接受该页面的LTPage对象
            layout = device.get_result()
            # 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象
            # 一般包括LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等等
            # 想要获取文本就获得对象的text属性,
            for x in layout:
                if(isinstance(x,LTTextBoxHorizontal)):
                    with open(r‘2.txt‘,‘a‘) as f:
                        results = x.get_text()
                        print(results)
                        f.write(results  +"\n")

if __name__ == ‘__main__‘:
    parse()
    time2 = time.time()
    print("总共消耗时间为:",time2-time1)

 

七   python读取PDF文档代码分析

  PDF格式不是规范格式. 尽管它被叫做"PDF文档", 但并不像word或者html文档。PDF的表现更像一张图片。PDF更像是在一张纸的各个准确的位置上把内容都摆放出来。大部分情况下,没有逻辑结构,比如句子或段落,并且不能自适应页面大小的调整。PDFMiner尝试通过猜测它们的布局来重建它们的结构,但是不保证一定能工作。我知道这样很难看,但是,PDF确实不够规范。

  下面这个图片是使用流程说明,我们将其分解来看

技术分享图片

 

    由于PDF文件有如此大和复杂的结构,完整解析PDF文件很费时费力。
好吧,大多数PDF工作中,很多模块是不需要加进来的。因此 PDFMiner 
采用了一个懒惰分析的策略,就是只分析所需要的部分。解析时候,至少
需要2个核心类,PDFParser 和 PDFDocument。这两个模块配合其他
模块来使用。



PDFParser     从文件中获取数据

PDFDocument   存储文档数据结构到内存中

PDFPageInterpreter 解析page内容

PDFDevice    把解析到的内容转化为你需要的东西

PDFResourceManager存储共享资源,例如字体或图片

  

技术分享图片

 

  首先使用 open 方法或者  urlopen  打开本场文档或者网络文档(一般会这么做因为考虑到文档太大,对网络服务器负担也很大)生成文档对象,以下的方法之中的网络链接已经存在了。

  

# 获取文档对象  
pdf0 = open(‘sampleFORtest.pdf‘,‘rb‘)  
# pdf1 = urlopen(‘http://www.tencent.com/20160321.pdf‘) 

  然后创建 文档解析器 和 PDF文档对象 并将他们相互关联

# 创建一个与文档关联的解析器  
parser = PDFParser(pdf0)  
  
# 创建一个PDF文档对象  
doc = PDFDocument()  
  
# 连接两者  
parser.set_document(doc)  
doc.set_parser(parser)  

  对 PDF文档对象 进行初始化,如果文档本身进行了加密,则需要在加入 password 参数

# 文档初始化  
doc.initialize(‘‘)  

  技术分享图片

  先创建 PDF资源管理器 和 参数分析器 

# 创建PDF资源管理器  
resources = PDFResourceManager()  
  
# 创建参数分析器  
laparam = LAParams()  

  再创建一个 聚合器 ,并接收 PDF资源管理器  参数分析器 作为参数

# 创建一个聚合器,并接收资源管理器,参数分析器作为参数  
device = PDFPageAggregator(resources,laparams=laparam) 

  最后创建一个 页面解释器 ,将 PDF资源管理器 和 聚合器 作为参数

# 创建一个页面解释器  
interpreter = PDFPageInterpreter(resources,device)  

  这样 页面解释器 就具有对PDF文档进行编码,解释成Python能够识别的格式

技术分享图片

 

   最后呢,使用 PDF文档对象 的 get_pages()方法 从PDF文档中读取出页面集合,接着使用 页面解释器    对页面集合逐一读取,再调用 聚合器  的 get_result()方法 将页面逐一放置到 layout 之中,最后商用 layout 的 get_text()方法 获取每一页的 text。

for page in doc.get_pages():  
    # 使用页面解释器读取页面  
    interpreter.process_page(page)  
    # 使用聚合器读取页面页面内容  
    layout = device.get_result()  
  
    for out in layout:  
        if hasattr(out,‘get_text‘):     # 因为文档中不只有text文本  
            print(out.get_text())  

  需要注意的是在PDF文档中不只有 text 还可能有图片等等,为了确保不出错先判断对象是否具有 get_text()方法 

 八,结果分析

  如果PDF文件中仅仅是文字,那么会完全解析出来,读出文字,存在一个TXT文档里面,但是要是出现了图片等东西,则不会读取到东西。

  本文做了三个实验,分别是PDF文档里面只存在文字,只存在图片,存在文字和图片。

  结果显示:

只存在文字的PDF 此程序会全部读取出文字
只存在图片的PDF 此程序不会读取出任何东西
存在图片和文字 此程序只会读出文字,不会识别图片

  所以说,图片的文字识别,不能只单纯的使用pdfminer这个库,还需要图片处理等相关技术。

深入学习python解析并读取PDF文件内容的方法

标签:layout   __init__   RoCE   rds   app   const   tor   word   params   

原文地址:https://www.cnblogs.com/wj-1314/p/9429816.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!