如何用Python批量提取PDF文本內容?

本文爲你展現,如何用Python把許多PDF文件的文本內容批量提取出來,而且整理存儲到數據框中,以便於後續的數據分析。python

問題

最近,讀者們在後臺的留言,愈發五花八門了。git

寫了幾篇關於天然語言處理的文章後,一種呼聲漸強:github

老師,pdf中的文本內容,有沒有什麼方便的方法提取出來呢?shell

我能體會到讀者的心情。數據庫

我展現的例子中,文本數據都是直接能夠讀入數據框工具作處理的。它們可能來自開放數據集合、網站API,或者爬蟲。瀏覽器

可是,有的時候,你會遇到須要處理指定格式數據的問題。安全

例如pdf。bash

許多的學術論文、研究報告,甚至是資料分享,都採用這種格式發佈。微信

這時候,已經掌握了諸多天然語言分析工具的你,會很有「拔劍四顧心茫然」的感受——明明知道如何處理其中的文本信息,但就是隔着一個格式轉換的問題,作不來。數據結構

怎麼辦?

辦法天然是有的,例如專用工具、在線轉換服務網站,甚至還能夠手動複製粘貼嘛。

可是,我們是看重效率的,對不對?

上述辦法,有的須要在網上傳輸大量內容,花費時間較多,並且可能帶來安全和隱私問題;有的須要專門花錢購買;有的乾脆就不現實。

怎麼辦?

好消息是,Python就能夠幫助你高效、快速地批量提取pdf文本內容,並且和數據整理分析工具無縫銜接,爲你後續的分析處理作好基礎服務工做。

本文給你詳細展現這一過程。

想不想試試?

數據

爲了更好地說明流程,我爲你準備好了一個壓縮包。

裏面包括本教程的代碼,以及咱們要用到的數據。

請你到 這個網址 下載本教程配套的壓縮包。

下載後解壓,你會在生成的目錄(下稱「演示目錄」)裏面看到如下內容。

演示目錄裏面包含:

  • Pipfile: pipenv 配置文件,用來準備我們變成須要用到的依賴包。後文會講解使用方法;
  • pdf_extractor.py: 利用pdfminer.six編寫的輔助函數。有了它你就能夠直接調用pdfminer提供的pdf文本內容抽取功能,而沒必要考慮一大堆惱人的參數;
  • demo.ipynb: 已經爲你寫好的本教程 Python 源代碼 (Jupyter Notebook格式)。

另外,演示目錄中還包括了2個文件夾。

這兩個文件夾裏面,都是中文pdf文件,用來給你展現pdf內容抽取。它們都是我幾年前發表的中文核心期刊論文。

這裏作2點說明:

  1. 使用我本身的論文作示例,是由於我怕用別人的論文作文本抽取,會與論文做者及數據庫運營商之間有知識產權的糾紛;
  2. 分紅2個文件夾,是爲了向你展現添加新的pdf文件時,抽取工具會如何處理。

pdf文件夾內容以下:

newpdf文件夾內容以下:

數據準備好了,下面咱們來部署代碼運行環境。

環境

要安裝Python,比較省事的辦法是裝Anaconda套裝。

請到 這個網址 下載Anaconda的最新版本。

請選擇左側的 Python 3.6 版本下載安裝。

若是你須要具體的步驟指導,或者想知道Windows平臺如何安裝並運行Anaconda命令,請參考我爲你準備的 視頻教程

安裝好Anaconda以後,打開終端,用cd命令進入演示目錄

若是你不瞭解具體使用方法,也能夠參考 視頻教程

咱們須要安裝一些環境依賴包。

首先執行:

pip install pipenv
複製代碼

這裏安裝的,是一個優秀的 Python 軟件包管理工具 pipenv 。 安裝後,請執行:

pipenv install --skip-lock
複製代碼

pipenv 工具會依照Pipfile,自動爲咱們安裝所須要的所有依賴軟件包。

終端裏面會有進度條,提示所需安裝軟件數量和實際進度。

裝好後,根據提示咱們執行:

pipenv shell
複製代碼

這樣,咱們就進入本教程專屬的虛擬運行環境了。

注意必定要執行下面這句:

python -m ipykernel install --user --name=py36
複製代碼

只有這樣,當前的Python環境纔會做爲核心(kernel)在系統中註冊,而且命名爲py36。

此處請確認你的電腦上已經安裝了 Google Chrome 瀏覽器。

咱們執行:

jupyter notebook
複製代碼

默認瀏覽器(Google Chrome)會開啓,並啓動 Jupyter 筆記本界面:

你能夠直接點擊文件列表中的第一項ipynb文件,能夠看到本教程的所有示例代碼。

你能夠一邊看教程的講解,一邊依次執行這些代碼。

可是,我建議的方法,是回到主界面下,新建一個新的空白 Python 3 筆記本(顯示名稱爲 py36 的那個)。

請跟着教程,一個個字符輸入相應的內容。這能夠幫助你更爲深入地理解代碼的含義,更高效地把技能內化。

當你在編寫代碼中遇到困難的時候,能夠返回參照 demo.ipynb 文件。

準備工做結束,下面咱們開始正式輸入代碼。

代碼

首先,咱們讀入一些模塊,以進行文件操做。

import glob
import os
複製代碼

前文提到過,演示目錄下,有兩個文件夾,分別是pdf和newpdf。

咱們指定 pdf 文件所在路徑爲其中的pdf文件夾。

pdf_path = "pdf/"
複製代碼

咱們但願得到全部 pdf 文件的路徑。用glob,一條命令就能完成這個功能。

pdfs = glob.glob("{}/*.pdf".format(pdf_path))
複製代碼

看看咱們得到的 pdf 文件路徑是否正確。

pdfs
複製代碼
['pdf/複雜系統仿真的微博客虛假信息擴散模型研究.pdf',
 'pdf/面向影子分析的社交媒體競爭情報蒐集.pdf',
 'pdf/面向人機協同的移動互聯網政務門戶探析.pdf']
複製代碼

經驗證。準確無誤。

下面咱們利用 pdfminer 來從 pdf 文件中抽取內容。咱們須要從輔助 Python 文件 pdf_extractor.py 中讀入函數 extract_pdf_content

from pdf_extractor import extract_pdf_content
複製代碼

用這個函數,咱們嘗試從 pdf 文件列表中的第一篇裏,抽取內容,而且把文本保存在 content 變量裏。

content = extract_pdf_content(pdfs[0])
複製代碼

咱們看看 content 裏都有什麼:

content
複製代碼

顯然,內容抽取並不完美,頁眉頁腳等信息都混了進來。

不過,對於咱們的許多文本分析用途來講,這可有可無。

你會看到 content 的內容裏面有許多的 \n,這是什麼呢?

咱們用 print 函數,來顯示 content 的內容。

print(content)
複製代碼

能夠清楚看到,那些 \n 是換行符。

經過一個 pdf 文件的抽取測試,咱們創建了信心。

下面,咱們該創建辭典,批量抽取和存儲內容了。

mydict = {}
複製代碼

咱們遍歷 pdfs 列表,把文件名稱(不包含目錄)做爲鍵值。這樣,咱們能夠很容易看到,哪些pdf文件已經被抽取過了,哪些尚未抽取。

爲了讓這個過程更爲清晰,咱們讓Python輸出正在抽取的 pdf 文件名。

for pdf in pdfs:
    key = pdf.split('/')[-1]
    if not key in mydict:
        print("Extracting content from {} ...".format(pdf))
        mydict[key] = extract_pdf_content(pdf)
複製代碼

抽取過程當中,你會看到這些輸出信息:

Extracting content from pdf/複雜系統仿真的微博客虛假信息擴散模型研究.pdf ...
Extracting content from pdf/面向影子分析的社交媒體競爭情報蒐集.pdf ...
Extracting content from pdf/面向人機協同的移動互聯網政務門戶探析.pdf ...
複製代碼

看看此時字典中的鍵值都有哪些:

mydict.keys()
複製代碼
dict_keys(['複雜系統仿真的微博客虛假信息擴散模型研究.pdf', '面向影子分析的社交媒體競爭情報蒐集.pdf', '面向人機協同的移動互聯網政務門戶探析.pdf'])
複製代碼

一切正常。

下面咱們調用pandas,把字典變成數據框,以利於分析。

import pandas as pd
複製代碼

下面這條語句,就能夠把字典轉換成數據框了。注意後面的reset_index()把原先字典鍵值生成的索引也轉換成了普通的列。

df = pd.DataFrame.from_dict(mydict, orient='index').reset_index()
複製代碼

而後咱們從新命名列,以便於後續使用。

df.columns = ["path", "content"]
複製代碼

此時的數據框內容以下:

df
複製代碼

能夠看到,咱們的數據框擁有了pdf文件信息和所有文本內容。這樣你就可使用關鍵詞抽取、情感分析、類似度計算等等諸多分析工具了。

篇幅所限,咱們這裏只用一個字符數量統計的例子來展現基本分析功能。

咱們讓 Python 幫咱們統計抽取內容的長度。

df["length"] = df.content.apply(lambda x: len(x))
複製代碼

此時的數據框內容發生如下變化:

df
複製代碼

多出的一列,就是 pdf 文本內容的字符數量。

爲了在 Jupyter Notebook 裏面正確展現繪圖結果,咱們須要使用如下語句:

%matplotlib inline
複製代碼

下面,咱們讓 Pandas 把字符長度一列的信息用柱狀圖標示出來。爲了顯示的美觀,咱們設置了圖片的長寬比例,而且把對應的pdf文件名稱以傾斜45度來展現。

import matplotlib.pyplot as plt
plt.figure(figsize=(14, 6))
df.set_index('path').length.plot(kind='bar')
plt.xticks(rotation=45)
複製代碼

可視化分析完成。

下面咱們把剛纔的分析流程整理成函數,以便於未來更方便地調用。

咱們先整合pdf內容提取到字典的模塊:

def get_mydict_from_pdf_path(mydict, pdf_path):
    pdfs = glob.glob("{}/*.pdf".format(pdf_path))
    for pdf in pdfs:
        key = pdf.split('/')[-1]
        if not key in mydict:
            print("Extracting content from {} ...".format(pdf))
            mydict[key] = extract_pdf_content(pdf)
    return mydict
複製代碼

這裏輸入是已有詞典和pdf文件夾路徑。輸出爲新的詞典。

你可能會納悶爲什麼還要輸入「已有詞典」。彆着急,一下子我用實際例子展現給你看。

下面這個函數很是直白——就是把詞典轉換成數據框。

def make_df_from_mydict(mydict):
    df = pd.DataFrame.from_dict(mydict, orient='index').reset_index()
    df.columns = ["path", "content"]
    return df
複製代碼

最後一個函數,用於繪製統計出來的字符數量。

def draw_df(df):
    df["length"] = df.content.apply(lambda x: len(x))
    plt.figure(figsize=(14, 6))
    df.set_index('path').length.plot(kind='bar')
    plt.xticks(rotation=45)
複製代碼

函數已經編好,下面咱們來嘗試一下。

還記得演示目錄下有個子目錄,叫作newpdf對吧?

咱們把其中的2個pdf文件,移動到pdf目錄下面。

這樣pdf目錄下面,就有了5個文件:

咱們執行新整理出的3個函數。

首先輸入已有的詞典(注意此時裏面已有3條記錄),pdf文件夾路徑沒變化。輸出是新的詞典。

mydict = get_mydict_from_pdf_path(mydict, pdf_path)
複製代碼
Extracting content from pdf/微博客 Twitter 的企業競爭情報蒐集.pdf ...
Extracting content from pdf/移動社交媒體用戶隱私保護對策研究.pdf ...
複製代碼

注意這裏的提示,原先的3個pdf文件沒有被再次抽取,只有2個新pdf文件被抽取。

我們這裏一共只有5個文件,因此你直觀上可能沒法感覺出顯著的區別。

可是,假設你原先已經用幾個小時,抽取了成百上千個pdf文件信息,結果你的老闆又丟給你3個新的pdf文件……

若是你必須從頭抽取信息,恐怕會很崩潰吧。

這時候,使用我們的函數,你能夠在1分鐘以內把新的文件內容追加進去。

這差異,不小吧?

下面咱們用新的詞典,構建數據框。

df = make_df_from_mydict(mydict)
複製代碼

咱們繪製新的數據框裏,pdf抽取文本字符數量。結果以下:

draw_df(df)
複製代碼

至此,代碼展現完畢。

小結

總結一下,本文爲你介紹瞭如下知識點:

  • 如何用glob批量讀取目錄下指定格式的文件路徑;
  • 如何用pdfminer從pdf文件中抽取文本信息;
  • 如何構建詞典,存儲與鍵值(本文中爲文件名)對應的內容,而且避免重複處理數據;
  • 如何將詞典數據結構輕鬆轉換爲Pandas數據框,以便於後續數據分析。
  • 如何用matplotlib和pandas自帶的繪圖函數輕鬆繪製柱狀統計圖形。

討論

你以前作的數據分析工做中,遇到過須要從pdf文件抽取文本的任務嗎?你是如何處理的?有沒有更好的工具與方法?歡迎留言,把你的經驗和思考分享給你們,咱們一塊兒交流討論。

喜歡請點贊。還能夠微信關注和置頂個人公衆號「玉樹芝蘭」(nkwangshuyi)

若是你對數據科學感興趣,不妨閱讀個人系列教程索引貼《如何高效入門數據科學?》,裏面還有更多的有趣問題及解法。

相關文章
相關標籤/搜索