數(shù)據(jù)分析入門——python提取PDF文本內(nèi)容

說真的,從PDF里面搜索關(guān)鍵字并提取上下文真的是個(gè)噩夢,PDF是個(gè)面向打印的文檔格式,從里面抓數(shù)據(jù)太痛苦了,搞了一天已經(jīng)想吐了。不過我還是沉淀了一點(diǎn)點(diǎn)東西。

python解析PDF文檔大致有以下幾個(gè)庫:

  • PDFMiner
  • pdfplumer
  • ta

我們主要是提取文本內(nèi)容,所以推薦使用pdfminer。

安裝

默認(rèn)使用python3.7的環(huán)境, 如果是2.7的請(qǐng)酌情處理。

pip install pdfminer
pip install pdfminer3k
pip install pdfminer.six

可能會(huì)用到的的相關(guān)類:

  • PDFParser: 從一個(gè)文件中獲取數(shù)據(jù)。
  • PDFDocument: 保存獲取的數(shù)據(jù),和PDFParser是相互關(guān)聯(lián)的。
  • PDFPageInterpreter: 處理頁面內(nèi)容。
  • PDFDevice: 將其翻譯成你需要的格式。
  • PDFResourceManager: 用于存儲(chǔ)共享資源,如字體或圖像。

準(zhǔn)備

這里有一個(gè)很重要的關(guān)于PDF文檔結(jié)構(gòu)的知識(shí),有助于你用代碼篩選出你想要的東西:


LTPage :表示整個(gè)頁??赡軙?huì)含有LTTextBox,LTFigure,LTImage,LTRect,LTCurve和LTLine子對(duì)象。
LTTextBox:表示一組文本塊可能包含在一個(gè)矩形區(qū)域。注意此box是由幾何分析中創(chuàng)建,并且不一定表示該文本的一個(gè)邏輯邊界。它包含LTTextLine對(duì)象的列表。使用 get_text()方法返回文本內(nèi)容。
LTTextLine :包含表示單個(gè)文本行LTChar對(duì)象的列表。字符對(duì)齊要么水平或垂直,取決于文本的寫入模式。使用get_text()方法返回文本內(nèi)容。
LTAnno:在文本中字母實(shí)際上被表示為Unicode字符串。需要注意的是,雖然一個(gè)LTChar對(duì)象具有實(shí)際邊界,LTAnno對(duì)象沒有,因?yàn)檫@些是“虛擬”的字符,根據(jù)兩個(gè)字符間的關(guān)系(例如,一個(gè)空格)由布局分析后插入。
LTImage:表示一個(gè)圖像對(duì)象。嵌入式圖像可以是JPEG或其它格式,但是目前PDFMiner沒有放置太多精力在圖形對(duì)象。
LTLine:代表一條直線??捎糜诜蛛x文本或附圖。
LTRect:表示矩形??捎糜诳蚣艿牧硪粓D片或數(shù)字。
LTCurve:表示一個(gè)通用的Bezier曲線
————————————————
版權(quán)聲明:本文為CSDN博主「周小董」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/xc_zhou/java/article/details/81009809

開始發(fā)車

真的想吐,本來想好好寫一下的,現(xiàn)在完全沒心情,直接上代碼吧。這個(gè)是我封裝的一個(gè)單獨(dú)的文件:

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


def get_file_list(root=".", file_suffix="*") -> list:
    """

    獲取指定目錄和指定文件類型的文件列表。

    :param root: 默認(rèn)為當(dāng)前目錄
    :param file_suffix: 文件名后綴,默認(rèn)為*
    :return: 返回指定目錄和指定文件類型的list
    """
    l = glob.glob("{}/*.".format(root) + file_suffix)
    return l


# 將一個(gè)pdf轉(zhuǎn)換成dict
def pdf_to_txt(file_path: str):
    """
    可以搜索指定PDF文件中含關(guān)鍵詞的段落內(nèi)容
    :param file_path: PDF文檔路徑
    :param key_words: 搜索的關(guān)鍵詞
    :return: Dict格式的搜索結(jié)果
    """
    # try:
    rs = {}
    my_pdf = open(file_path, 'rb')
    print("File:", file_path)
    # 創(chuàng)建一個(gè)文檔解析器
    par = PDFParser(my_pdf)
    # 創(chuàng)建一個(gè)PDF文檔對(duì)象存儲(chǔ)文檔結(jié)構(gòu)
    my_doc = PDFDocument(par)
    # 判斷文件是否允許文本提取
    if not my_doc.is_extractable:
        raise PDFTextExtractionNotAllowed
    else:
        # 創(chuàng)建一個(gè)PDF資源管理器對(duì)象用來存儲(chǔ)資源
        res = PDFResourceManager()
        # 設(shè)定參數(shù)進(jìn)行分析
        la = LAParams()
        # 創(chuàng)建一個(gè)PDF設(shè)備對(duì)象
        dev = PDFPageAggregator(res, laparams=la)
        # 創(chuàng)建一個(gè)PDF解釋器對(duì)象
        my_interpreter = PDFPageInterpreter(res, dev)
        # return PDFPage.create_pages(my_doc)
        # 按頁開始處理
        for pg in PDFPage.create_pages(my_doc):
            my_interpreter.process_page(pg)
            lt_dict = {}
            rs[pg.pageid] = lt_dict
            print("Page ID:", pg.pageid)
            # 接收改頁面的LTPage對(duì)象
            lt = dev.get_result()
            for l in lt:
                if isinstance(l, LTTextBox):
                    # splitlines方法用來處理 \n 換行符
                    lt_dict[l.index] = l.get_text().splitlines()

    return rs


# 從上面轉(zhuǎn)換出來的字典中搜索關(guān)鍵字并返回它所在的LTTextBox內(nèi)容以及下一個(gè)LTTextBox的內(nèi)容,別問我為什么,我想吐~~
def search_keywords(the_dict: dict, keywords: str):
    """
    在指定的PDF轉(zhuǎn)成的dict中搜索關(guān)鍵詞,并返回其上下文

    :param the_dict: 必須是用本文件中的pdf_to_txt方法返回的字典才可以
    :param keywords: 要搜索的關(guān)鍵字
    :return: dict形式返回搜索結(jié)果
    """
    s = {}

    for key, value in the_dict.items():
        # print("koala", key, value)
        if keywords in value:
            s[key - 1] = the_dict[key - 1]
            s[key] = value
            s[key + 1] = the_dict[key + 1]
            print("Bingo!", key, value)
    if len(s) > 0:
        rs = {keywords: s}
        return rs

注釋寫的非常詳細(xì)了,雖然折騰了快一天,試來試去,但最后剩下的代碼還是比較精簡的,踩了不少坑。

以下是一個(gè)demo,演示如何調(diào)用上面封裝好的方法:

fl = pdfTools.get_file_list(file_suffix="pdf")

key_words = "我是關(guān)鍵字"

s = {fl[0]: pdfTools.pdf_to_txt(fl[0])}

aa =[]

for key, value in s[fl[0]].items():
    aa.append(pdfTools.search_keywords(value, key_words))

我不喜歡輸入到控制臺(tái)或者文件,因?yàn)橛胮yCharm,可以直接看到Jupyter Server上的變量值。

從PDF里面找東西真的真的太痛苦了,要是有高手有更好的方法求指教,謝了謝了!

有心情的時(shí)候也許我會(huì)再完善一下這篇文章吧,今天就這樣了,我去吐會(huì)兒~~~~~

再次聲明一下,本文參考了此篇文章部分內(nèi)容:[312]python提取pdf文本內(nèi)容,不要來找我麻煩,我沒工夫應(yīng)付。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概要 64學(xué)時(shí) 3.5學(xué)分 章節(jié)安排 電子商務(wù)網(wǎng)站概況 HTML5+CSS3 JavaScript Node 電子...
    阿啊阿吖丁閱讀 9,851評(píng)論 0 3
  • 原諒把你帶走的雨天,在漸漸模糊的窗前。每個(gè)人最后都要說,再見。 再遇見,見抑或不見? ?第一章? 柯健第一次遇見蕭...
    夢1212閱讀 509評(píng)論 0 2
  • 謙謙君子,窈窕淑女,人皆好之。每個(gè)人心中可能都有自己理想的朋友,家人,另一半的模樣,但如果發(fā)現(xiàn)她不是你理想的...
    不妖陌諾閱讀 462評(píng)論 10 9

友情鏈接更多精彩內(nèi)容