本文為你展示爵赵,如何用Python把許多PDF文件的文本內(nèi)容批量提取出來泊脐,并且整理存儲到數(shù)據(jù)框中晨抡,以便于后續(xù)的數(shù)據(jù)分析则剃。
問題
最近棍现,讀者們在后臺的留言己肮,愈發(fā)五花八門了。
寫了幾篇關于自然語言處理的文章后娄柳,一種呼聲漸強:
老師赤拒,pdf中的文本內(nèi)容,有沒有什么方便的方法提取出來呢这敬?
我能體會到讀者的心情崔涂。
我展示的例子中冷蚂,文本數(shù)據(jù)都是直接可以讀入數(shù)據(jù)框工具做處理的觅闽。它們可能來自開放數(shù)據(jù)集合蛉拙、網(wǎng)站API,或者爬蟲吮廉。
但是宦芦,有的時候调卑,你會遇到需要處理指定格式數(shù)據(jù)的問題大咱。
例如pdf碴巾。
許多的學術論文厦瓢、研究報告,甚至是資料分享劳跃,都采用這種格式發(fā)布刨仑。
這時候贸人,已經(jīng)掌握了諸多自然語言分析工具的你,會頗有“拔劍四顧心茫然”的感覺——明明知道如何處理其中的文本信息倘要,但就是隔著一個格式轉(zhuǎn)換的問題封拧,做不來泽西。
怎么辦缰趋?
辦法自然是有的秘血,例如專用工具灰粮、在線轉(zhuǎn)換服務網(wǎng)站,甚至還可以手動復制粘貼嘛熔脂。
但是霞揉,咱們是看重效率的零聚,對不對些侍?
上述辦法岗宣,有的需要在網(wǎng)上傳輸大量內(nèi)容耗式,花費時間較多刊咳,而且可能帶來安全和隱私問題;有的需要專門花錢購買余指;有的干脆就不現(xiàn)實酵镜。
怎么辦淮韭?
好消息是贴届,Python就可以幫助你高效毫蚓、快速地批量提取pdf文本內(nèi)容绍些,而且和數(shù)據(jù)整理分析工具無縫銜接柬批,為你后續(xù)的分析處理做好基礎服務工作。
本文給你詳細展示這一過程嗅虏。
想不想試試皮服?
數(shù)據(jù)
為了更好地說明流程龄广,我為你準備好了一個壓縮包择同。
里面包括本教程的代碼敲才,以及我們要用到的數(shù)據(jù)。
請你到 這個網(wǎng)址 下載本教程配套的壓縮包剃氧。
下載后解壓她我,你會在生成的目錄(下稱“演示目錄”)里面看到以下內(nèi)容番舆。
演示目錄里面包含:
- Pipfile: pipenv 配置文件恨狈,用來準備咱們變成需要用到的依賴包禾怠。后文會講解使用方法吗氏;
-
pdf_extractor.py
: 利用pdfminer.six編寫的輔助函數(shù)弦讽。有了它你就可以直接調(diào)用pdfminer提供的pdf文本內(nèi)容抽取功能往产,而不必考慮一大堆惱人的參數(shù)某宪; -
demo.ipynb
: 已經(jīng)為你寫好的本教程 Python 源代碼 (Jupyter Notebook格式)兴喂。
另外衣迷,演示目錄中還包括了2個文件夾蘑险。
這兩個文件夾里面佃迄,都是中文pdf文件呵俏,用來給你展示pdf內(nèi)容抽取。它們都是我?guī)啄昵鞍l(fā)表的中文核心期刊論文吼肥。
這里做2點說明:
- 使用我自己的論文做示例缀皱,是因為我怕用別人的論文做文本抽取啤斗,會與論文作者及數(shù)據(jù)庫運營商之間有知識產(chǎn)權的糾紛钮莲;
- 分成2個文件夾崔拥,是為了向你展示添加新的pdf文件時链瓦,抽取工具會如何處理澡绩。
pdf文件夾內(nèi)容如下:
newpdf文件夾內(nèi)容如下:
數(shù)據(jù)準備好了肥卡,下面我們來部署代碼運行環(huán)境步鉴。
環(huán)境
要安裝Python氛琢,比較省事的辦法是裝Anaconda套裝阳似。
請到 這個網(wǎng)址 下載Anaconda的最新版本撮奏。
請選擇左側(cè)的 Python 3.6 版本下載安裝泽疆。
如果你需要具體的步驟指導玲献,或者想知道Windows平臺如何安裝并運行Anaconda命令捌年,請參考我為你準備的 視頻教程 礼预。
安裝好Anaconda之后逆瑞,打開終端获高,用cd命令進入演示目錄念秧。
如果你不了解具體使用方法摊趾,也可以參考 視頻教程 砾层。
我們需要安裝一些環(huán)境依賴包肛炮。
首先執(zhí)行:
pip install pipenv
這里安裝的侨糟,是一個優(yōu)秀的 Python 軟件包管理工具 pipenv 秕重。
安裝后,請執(zhí)行:
pipenv install --skip-lock
pipenv 工具會依照Pipfile服鹅,自動為我們安裝所需要的全部依賴軟件包菱魔。
終端里面會有進度條,提示所需安裝軟件數(shù)量和實際進度杰妓。
裝好后巷挥,根據(jù)提示我們執(zhí)行:
pipenv shell
這樣倍宾,我們就進入本教程專屬的虛擬運行環(huán)境了高职。
注意一定要執(zhí)行下面這句:
python -m ipykernel install --user --name=py36
只有這樣怔锌,當前的Python環(huán)境才會作為核心(kernel)在系統(tǒng)中注冊埃元,并且命名為py36岛杀。
此處請確認你的電腦上已經(jīng)安裝了 Google Chrome 瀏覽器楞件。
我們執(zhí)行:
jupyter notebook
默認瀏覽器(Google Chrome)會開啟土浸,并啟動 Jupyter 筆記本界面:
你可以直接點擊文件列表中的第一項ipynb文件黄伊,可以看到本教程的全部示例代碼墓阀。
你可以一邊看教程的講解斯撮,一邊依次執(zhí)行這些代碼勿锅。
但是,我建議的方法枣氧,是回到主界面下溢十,新建一個新的空白 Python 3 筆記本(顯示名稱為 py36 的那個)。
請跟著教程达吞,一個個字符輸入相應的內(nèi)容张弛。這可以幫助你更為深刻地理解代碼的含義,更高效地把技能內(nèi)化酪劫。
當你在編寫代碼中遇到困難的時候,可以返回參照 demo.ipynb
文件覆糟。
準備工作結(jié)束刻剥,下面我們開始正式輸入代碼。
代碼
首先搪桂,我們讀入一些模塊透敌,以進行文件操作。
import glob
import os
前文提到過踢械,演示目錄下酗电,有兩個文件夾,分別是pdf和newpdf内列。
我們指定 pdf 文件所在路徑為其中的pdf
文件夾撵术。
pdf_path = "pdf/"
我們希望獲得所有 pdf 文件的路徑。用glob话瞧,一條命令就能完成這個功能嫩与。
pdfs = glob.glob("{}/*.pdf".format(pdf_path))
看看我們獲得的 pdf 文件路徑是否正確。
pdfs
['pdf/復雜系統(tǒng)仿真的微博客虛假信息擴散模型研究.pdf',
'pdf/面向影子分析的社交媒體競爭情報搜集.pdf',
'pdf/面向人機協(xié)同的移動互聯(lián)網(wǎng)政務門戶探析.pdf']
經(jīng)驗證交排。準確無誤划滋。
下面我們利用 pdfminer 來從 pdf 文件中抽取內(nèi)容。我們需要從輔助 Python 文件 pdf_extractor.py
中讀入函數(shù) extract_pdf_content
埃篓。
from pdf_extractor import extract_pdf_content
用這個函數(shù)处坪,我們嘗試從 pdf 文件列表中的第一篇里,抽取內(nèi)容,并且把文本保存在 content 變量里同窘。
content = extract_pdf_content(pdfs[0])
我們看看 content 里都有什么:
content
顯然玄帕,內(nèi)容抽取并不完美,頁眉頁腳等信息都混了進來想邦。
不過裤纹,對于我們的許多文本分析用途來說,這無關緊要丧没。
你會看到 content 的內(nèi)容里面有許多的 \n
鹰椒,這是什么呢?
我們用 print
函數(shù)骂铁,來顯示 content 的內(nèi)容吹零。
print(content)
可以清楚看到罩抗,那些 \n
是換行符拉庵。
通過一個 pdf 文件的抽取測試,我們建立了信心套蒂。
下面钞支,我們該建立辭典,批量抽取和存儲內(nèi)容了操刀。
mydict = {}
我們遍歷 pdfs 列表烁挟,把文件名稱(不包含目錄)作為鍵值。這樣骨坑,我們可以很容易看到撼嗓,哪些pdf文件已經(jīng)被抽取過了,哪些還沒有抽取欢唾。
為了讓這個過程更為清晰且警,我們讓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/復雜系統(tǒng)仿真的微博客虛假信息擴散模型研究.pdf ...
Extracting content from pdf/面向影子分析的社交媒體競爭情報搜集.pdf ...
Extracting content from pdf/面向人機協(xié)同的移動互聯(lián)網(wǎng)政務門戶探析.pdf ...
看看此時字典中的鍵值都有哪些:
mydict.keys()
dict_keys(['復雜系統(tǒng)仿真的微博客虛假信息擴散模型研究.pdf', '面向影子分析的社交媒體競爭情報搜集.pdf', '面向人機協(xié)同的移動互聯(lián)網(wǎng)政務門戶探析.pdf'])
一切正常斑芜。
下面我們調(diào)用pandas,把字典變成數(shù)據(jù)框祟霍,以利于分析杏头。
import pandas as pd
下面這條語句,就可以把字典轉(zhuǎn)換成數(shù)據(jù)框了沸呐。注意后面的reset_index()
把原先字典鍵值生成的索引也轉(zhuǎn)換成了普通的列醇王。
df = pd.DataFrame.from_dict(mydict, orient='index').reset_index()
然后我們重新命名列,以便于后續(xù)使用崭添。
df.columns = ["path", "content"]
此時的數(shù)據(jù)框內(nèi)容如下:
df
可以看到寓娩,我們的數(shù)據(jù)框擁有了pdf文件信息和全部文本內(nèi)容。這樣你就可以使用關鍵詞抽取、情感分析根暑、相似度計算等等諸多分析工具了力试。
篇幅所限,我們這里只用一個字符數(shù)量統(tǒng)計的例子來展示基本分析功能排嫌。
我們讓 Python 幫我們統(tǒng)計抽取內(nèi)容的長度畸裳。
df["length"] = df.content.apply(lambda x: len(x))
此時的數(shù)據(jù)框內(nèi)容發(fā)生以下變化:
df
多出的一列,就是 pdf 文本內(nèi)容的字符數(shù)量淳地。
為了在 Jupyter Notebook 里面正確展示繪圖結(jié)果怖糊,我們需要使用以下語句:
%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)
可視化分析完成扰魂。
下面我們把剛才的分析流程整理成函數(shù),以便于將來更方便地調(diào)用蕴茴。
我們先整合pdf內(nèi)容提取到字典的模塊:
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文件夾路徑劝评。輸出為新的詞典。
你可能會納悶為何還要輸入“已有詞典”倦淀。別著急蒋畜,一會兒我用實際例子展示給你看。
下面這個函數(shù)非常直白——就是把詞典轉(zhuǎn)換成數(shù)據(jù)框撞叽。
def make_df_from_mydict(mydict):
df = pd.DataFrame.from_dict(mydict, orient='index').reset_index()
df.columns = ["path", "content"]
return df
最后一個函數(shù)姻成,用于繪制統(tǒng)計出來的字符數(shù)量。
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)
函數(shù)已經(jīng)編好愿棋,下面我們來嘗試一下科展。
還記得演示目錄下有個子目錄,叫做newpdf
對吧初斑?
我們把其中的2個pdf文件辛润,移動到pdf目錄下面。
這樣pdf目錄下面见秤,就有了5個文件:
我們執(zhí)行新整理出的3個函數(shù)砂竖。
首先輸入已有的詞典(注意此時里面已有3條記錄),pdf文件夾路徑?jīng)]變化鹃答。輸出是新的詞典乎澄。
mydict = get_mydict_from_pdf_path(mydict, pdf_path)
Extracting content from pdf/微博客 Twitter 的企業(yè)競爭情報搜集.pdf ...
Extracting content from pdf/移動社交媒體用戶隱私保護對策研究.pdf ...
注意這里的提示,原先的3個pdf文件沒有被再次抽取测摔,只有2個新pdf文件被抽取置济。
咱們這里一共只有5個文件解恰,所以你直觀上可能無法感受出顯著的區(qū)別。
但是浙于,假設你原先已經(jīng)用幾個小時护盈,抽取了成百上千個pdf文件信息,結(jié)果你的老板又丟給你3個新的pdf文件……
如果你必須從頭抽取信息羞酗,恐怕會很崩潰吧腐宋。
這時候,使用咱們的函數(shù)檀轨,你可以在1分鐘之內(nèi)把新的文件內(nèi)容追加進去胸竞。
這差別,不小吧参萄?
下面我們用新的詞典卫枝,構建數(shù)據(jù)框。
df = make_df_from_mydict(mydict)
我們繪制新的數(shù)據(jù)框里讹挎,pdf抽取文本字符數(shù)量校赤。結(jié)果如下:
draw_df(df)
至此,代碼展示完畢淤袜。
小結(jié)
總結(jié)一下痒谴,本文為你介紹了以下知識點:
- 如何用glob批量讀取目錄下指定格式的文件路徑衰伯;
- 如何用pdfminer從pdf文件中抽取文本信息铡羡;
- 如何構建詞典,存儲與鍵值(本文中為文件名)對應的內(nèi)容意鲸,并且避免重復處理數(shù)據(jù)烦周;
- 如何將詞典數(shù)據(jù)結(jié)構輕松轉(zhuǎn)換為Pandas數(shù)據(jù)框,以便于后續(xù)數(shù)據(jù)分析怎顾。
- 如何用matplotlib和pandas自帶的繪圖函數(shù)輕松繪制柱狀統(tǒng)計圖形读慎。
討論
你之前做的數(shù)據(jù)分析工作中,遇到過需要從pdf文件抽取文本的任務嗎槐雾?你是如何處理的夭委?有沒有更好的工具與方法癌压?歡迎留言辅髓,把你的經(jīng)驗和思考分享給大家,我們一起交流討論拉鹃。
喜歡請點贊擎值。還可以微信關注和置頂我的公眾號“玉樹芝蘭”(nkwangshuyi)慌烧。
如果你對數(shù)據(jù)科學感興趣,不妨閱讀我的系列教程索引貼《如何高效入門數(shù)據(jù)科學鸠儿?》屹蚊,里面還有更多的有趣問題及解法厕氨。