深刻學習python解析並讀取PDF文件內容的方法

  這篇文章主要學習了python解析並讀取PDF文件內容的方法,包括對學習庫的應用,python2.7和python3.6中python解析PDF文件內容庫的更新,包括對pdfminer庫的詳細解釋和應用。主要參考了一些已有的博客內容,代碼。html

  主要思路是首先利用一個作項目的形式,描述所作的問題,運行環境,和須要安裝的庫,而後寫代碼,此代碼是在python2.7中運行,小編也寫出在python3.6中運行的代碼,並詳細解釋python2.7和python3.6中python庫的一些不一樣之處,最後詳細的解釋了代碼的意思,和庫的思路,最終的目的就讓咱們理解,並學會應用python解析並讀取PDF文件內容的方法。python

一,問題描述

  利用python讀取PDF文本內容服務器

二,運行環境

  python 3.6網絡

三, 須要安裝的庫

pip install pdfminer

  對pdfminer的簡單介紹,官網介紹以下:數據結構

  PDFMiner is a tool for extracting information from PDF documents. Unlike other PDF-related tools, it focuses entirely on getting and analyzing text data. PDFMiner allows to obtain the exact location of texts in a page, as well as other information such as fonts or lines. It includes a PDF converter that can transform PDF files into other text formats (such as HTML). It has an extensible PDF parser that can be used for other purposes instead of text analysis.python2.7

翻譯是這樣的:工具

PDFMiner是一個從PDF文檔中提取信息的工具。與其餘pdf相關的
工具不一樣,它徹底專一於獲取和分析文本數據。PDFMiner容許獲取
頁面中文本的確切位置,以及其餘信息,好比字體或行。它包括一
個PDF轉換器,能夠將PDF文件轉換成其餘文本格式(如HTML)。
它有一個可擴展的PDF解析器,能夠用於其餘目的而不是文本分析。

  

四,實現源代碼(其中代碼1和代碼2都是python2.7實現的)

python2中相關庫的安裝

  python各類庫下載地址:佈局

https://www.lfd.uci.edu/~gohlke/pythonlibs/學習

https://pypi.python.org/pypi/測試

找到pdfminer,下載,而後上傳到服務器上,直接安裝便可。

  可是因爲Python2和python3版本之間的不兼容,因此對應不一樣的版本,咱們這裏須要使用不一樣的特定環境。

    其中的Pdfminer版本是pdfminer 20140328(對於python2.x的測試沒有任何問題)

#_*_coding:utf-8_*_

from pdfminer.pdfparser import  PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfdevice import PDFDevice
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTTextBoxHorizontal,LAParams
from pdfminer.pdfpage import PDFTextExtractionNotAllowed


def parse(Path,Save_name):
   
    parser = PDFParser(Path)
    document = PDFDocument(parser)
 

    if not document.is_extractable:
        raise PDFTextExtractionNotAllowed
    else:
        rsrcmgr = PDFResourceManager()
        laparams = LAParams()
        device = PDFPageAggregator(rsrcmgr,laparams=laparams)
        interpreter = PDFPageInterpreter(rsrcmgr,device)

        for page in PDFPage.create_pages(document):
            interpreter.process_page(page)
            layout = device.get_result()
            for x in layout:
                if(isinstance(x,LTTextBoxHorizontal)):
                    with open('%s'%(Save_name),'a') as f:
			results = x.get_text().encode('utf-8')
                        f.write(results  +"\n")

if __name__ == '__main__':
    Path = open('word1-words.pdf','rb')
    parse(Path,'1.txt')

  

 

五,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這個庫,還須要圖片處理等相關技術。

九,PDF解析模塊-PDFMiner開發手冊

 

PDF格式不是規範格式. 儘管它被叫作"PDF文檔", 但並不像word或者html文檔。PDF的表現更像一張圖片。PDF更像是在一張紙的各個準確的位置上把內容都擺放出來。大部分狀況下,沒有邏輯結構,好比句子或段落,而且不能自適應頁面大小的調整。PDFMiner嘗試經過猜想它們的佈局來重建它們的結構,可是不保證必定能工做。我知道這樣很難看,可是,PDF確實不夠規範。

 

更多關於PDF內部結構的技術詳情,請見《如何手工提取PDF內容》。

http://www.youtube.com/watch?v=k34wRxaxA_c
http://www.youtube.com/watch?v=_A1M4OdNsiQ
http://www.youtube.com/watch?v=sfV_7cWPgZE

 

因爲PDF文件有如此大和複雜的結構,完整解析PDF文件很費時費力。好吧,大多數PDF工做中,不少模塊是不須要加進來的。所以 PDFMiner 採用了一個懶惰分析的策略,就是隻分析所須要的部分。解析時候,至少須要2個核心類,PDFParser 和 PDFDocument。這兩個模塊配合其餘模塊來使用。

 

PDFParser     從文件中獲取數據

PDFDocument   存儲文檔數據結構到內存中

PDFPageInterpreter 解析page內容

PDFDevice    把解析到的內容轉化爲你須要的東西

PDFResourceManager存儲共享資源,例如字體或圖片

 

佈局分析把pdf文檔中每一頁返回爲一個 LTPage 對象. 該對象包含該頁面中的子對象,格式化爲樹形結構。

下圖顯示了這些對象之間的關係。

 


 

 

 

LTPage

表明一個完整的頁面。能夠包含子對象,例如LTTextBox,LTFigure,LTImage,LTRect,LTCurve和LTLine.

LTTextBox
它包含 LTTextLine 對象的列表
表明一組被包含在矩形區域中的文本
須要注意的是,該box是根據幾何學分析獲得的,並不必定準確地表現爲該文本的邏輯範圍
get_text()方法能夠返回文本內容

LTTextLine
包含一個LTChar對象的列表,表現爲單行文本
字符表現爲一行或一列,取決於文本書寫方式
get_text()方法返回文本內容

LTChar / LTAnno
表明一個在文本中的真實的字母,做爲一個unicode字符串
LTChar 對象有真實的分隔符
LTAnno 對象沒有,是虛擬分隔符,按照兩個字符之間的關係,佈局分析器插入虛擬分隔符

LTFigure
表明一個被PDF Form對象使用的區域
pdf form適用於目前的圖表(present figures)或者頁面中植入的另外一個pdf文檔圖片。LTFigure對象能夠遞歸

LTImage
表明一個圖形對象。能夠是JPEG或者其餘格式,但PDFMiner目前沒有花太多精力在圖形對象上。

LTLine
表明一根直線。用來分割文本或圖表(figures)。

LTRect
表明一個矩形。
用來框住別的圖片或者圖表。

LTCurve
表明一個貝塞爾曲線。

也能夠從下面URL得到更多完整的示例。

 

http://denis.papathanasiou.org/?p=343

相關文章
相關標籤/搜索