本文首發於編程派的微信公衆號,搜索“codingpy”關注編程派吧。
2015年,美國官方解密了一系列有關本·拉登的文件,其中最引人矚目的,是美國國家情報總監辦公室(The Office of the Director of National Intelligence)在其官網上列出的“本·拉登的書架”。
曝光的這份閱讀清單涉及書籍和其他材料400餘種。其中包含了已解密的書信等文檔103份、公開發表的美國政府文件75份、英文書籍39冊、恐怖組織發表的材料35份、與法國有關的材料19份、媒體文章33篇、其他宗教文檔11份、智庫或其他研究40種、軟件或技術手冊30份,及一些零散資料。
在本文中,我們將學習如何分析PDF文檔,並且利用AlchemyAPI來進行實體抽取分析,看看本·拉登在這些信件中最常提到的10個實體是什麼。
AlchemyAPI是IBM旗下的一家公司,具有深度學習的自然語言處理和圖片識別技術,可利用人工智能分析理解網頁、文檔、電子郵件、微博等形式的內容。它還將同Google 一樣的神經網絡分析技術應用其中。
AlchemyAPI目前共提供了12個文本分析功能:實體抽取(entitiy extraction),情感分析,關鍵字抓取,概念標識,關係提取,分類識別,作者提取,語言識別,文本提取,微格式分析,訂閱內容識別,數據連接等。
接下來,我們開始進行準備工作。
本文中的代碼大部分來自automatingosint,我對源代碼進行更新。目前的腳本支持Python 3。
安裝依賴包
由於美國ODNI公開的本·拉登信件都是PDF格式的,因此我們首先必須要安裝能夠處理PDF文檔的Python包。這裏,我使用的是PyPDF2。我們通過pip
包管理器進行安裝:
pip install pypdf2
另外,你肯定不想一封一封地手動103封書信吧?!省時省力的辦法就是寫個腳本把這些文檔都爬取下來。由於要訪問網頁和解析網頁,我們選擇使用兩個常用的第三方庫:requests和BeautifulSoup 4:
pip install requests beautifulsoup4
獲取免費AlchemyAPI Key
AlchemyAPI是IBM旗下的一家公司,具有深度學習的自然語言處理和圖片識別技術,可利用人工智能分析理解網頁、文檔、電子郵件、微博等形式的內容。它還將同Google 一樣的神經網絡分析技術應用其中。AlchemyAPI目前共提供了12個文本分析功能:實體抽取(entitiy extraction),情感分析,關鍵字抓取,概念標識,關係提取,分類識別,作者提取,語言識別,文本提取,微格式分析,訂閱內容識別,數據連接等。
AlchemyAPI有一個免費的基礎服務包,每天的事務處理上限爲1000次。在本文中,我們將使用他們的實體抽取服務來執行文本分析。
獲取免費AlchemyAPI Key非常簡單,只需要填寫一個表單即可,輸入自己的郵箱地址。
申請處理完成之後,你就可以在郵箱中看到發送給你的API Key了。
安裝Alchemy Python SDK
獲得API Key之後,我們可以通過AlchemyAPI提供的Python SDK和HTTP REST接口調用其提供的文本分析服務。在本文中,我們選擇安裝SDK的方式。
PyPI上之前有AlchemyAPI包,但是後來移除了下載包,因此我們不能使用pip來安裝,只能通過Git克隆Python SDK的代碼庫或是直接下載代碼庫:
git clone https://github.com/AlchemyAPI/alchemyapi_python.git
接下來,我們要把申請到的API Key與SDK關聯起來。打開終端,進入SDK文件夾,然後按下面的示例執行alchemyapi.py文件:
cd alchemyapi_python python alchemyapi.py YOUR_API_KEY # 將YOUR_API_KEY替換成你收到的Key
爲確保SDK正常安裝,可以按照提示運行example.py查看演示程序:
python example.py
如果最後出現了下圖的文字,就證明SDK安裝正確,API Key也可以使用。
下載文檔
然後就到了怎麼自動將103份PDF文檔下載到本地了。
我們可以寫一個簡單的Python腳本來完成這項工作,但是我選擇把它封裝在download_bld_documents這個函數裏,因爲我想把所有的代碼都放在一個腳本里,這樣大家就可以直接運行這個腳本,等待一段時間,就可以看到最後的結果了。
這個函數寫的比較簡單,但是已經能夠滿足我們的需求了。
def download_bld_documents(): """Download Bin Laden's Declassified documents from ODNI.""" import os import time import requests from bs4 import BeautifulSoup # 創建一個名爲“pdfs”的文件夾,用於保存所有下載的PDF文檔。 try: os.mkdir("pdfs") except: pass # 獲取ODNI網站上有關本·拉登書架的網頁, # 將其交給Beautiful Soup,以進行HTML解析。 response = requests.get( "http://www.dni.gov/index.php/resources/bin-laden-bookshelf?start=1") if response.status_code == 200: html = BeautifulSoup(response.content) link_list = [] # 從網頁中第54個超鏈接開始,我們遍歷所有的文檔鏈接, # 僅保留那些我們所需要的鏈接:即含有“pdf”但不包含“Arabic” # 字樣的鏈接。我們將滿足要求的鏈接保存到列表`link_list`中。 for i in html.findAll("a")[54:]: if "pdf" in i['href'] and "Arabic" not in i.text: link_list.append("http://www.odni.gov%s" % i['href']) # 接下來,我們遍歷列表中所有的元素, # 從原鏈接中獲取PDF的文件名, #然後從ODNI網站下載相應的文檔。 for i in link_list: response = requests.get(i) file_name = i.split("/")[::-1][0] fd = open("pdfs/%s" % file_name, "wb") fd.write(response.content) fd.close() time.sleep(1)
由於文件數量比較多,因此在最終執行腳本時,耗費在文件下載的時間可能會比較長。如果你從ODNI網站下載的速度非常慢,那麼可以前往我的百度網盤下載,但是在最終執行時要對腳本做修改。只需要執行下文中的函數即可。
在微信號中,回覆“laden”即可獲得分享鏈接及提取碼。
處理文檔
下面,我們就可以正式對下載的PDF文檔進行分析了。我們將要利用Alchemy API提供的強大工具,對這些PDF文檔進行實體抽取(entitiy extraction)分析。通過實體分析,我們可以瞭解本·拉登在這些信件和文件中,談到最多的人、地方或東西是什麼。
所以,我們要一一打開這些PDF文件,從文檔中提取所有的文本,然後將其提交至Alchemy進行分析處理。在處理每一個文檔時,我們可以得到其中的實體數據,最後將所有文檔的分析數據結合在一起,就可以得到出現頻率最高的實體了。
我們將這部分代碼封裝在process_documents函數中:
def process_documents(): """Process downloaded documents using AlchemyAPI.""" # 導入所需要的模塊,包括我們安裝的PyPDF2和AlchemyAPI。 import PyPDF2 import glob import time from collections import Counter from alchemyapi import AlchemyAPI alchemyapi = AlchemyAPI() # 初始化AlchemyAPI。 file_list = glob.glob("pdfs/*.pdf") # 通過`glob`模塊獲取我們下載的所有PDF文件的文件名。 entities = {} # 我們要使用`entities`字典來保存每個PDF文檔的分析結果。 # 下面的for循環將遍歷所有的PDF文件 for pdf_file in file_list: # read in the PDF print("[*] Parsing %s" % pdf_file) # 初始化一個PyPDF2對象,用於保存從PDF文檔中提取的文本數據 pdf_obj = PyPDF2.PdfFileReader(open(pdf_file, "rb")) # 創建一個空字符串,用於後續構建這個PDF的全部文本數據 full_text = "" # 從每頁中提取文本數據 for page in pdf_obj.pages: full_text += page.extractText() # 接下來我們使用Alchemy API進行實體抽取 print("[*] Sending %d bytes to the Alchemy API" % len(full_text)) # 調用AlchemyAPI,並明確我們提交的是文本數據(第一個參數) # 然後傳入需要分析的文本,第三個參數代表禁用情感分析功能, # 因爲本文中我們只關注頻率最��的實體。 response = alchemyapi.entities('text', full_text, {'sentiment': 0}) if response['status'] == 'OK': # 遍歷返回的全部實體數據。 # Alchemy返回的每個實體中,都包含有`count`數據, # 我們要確保在`entities`字典中,將所有相同實體的count相加 for entity in response['entities']: # add each entity to our master list if entity['text'] in entities: entities[entity['text']] += int(entity['count']) else: entities[entity['text']] = int(entity['count']) print("[*] Retrieved %d entities from %s" % (len(entities), pdf_file)) else: print("[!] Error receiving Alchemy response: %s" % response['statusInfo']) time.sleep(1) # 上面的循環執行結束,我們可以統計最常見的實體, # 並把相關的結果打印出來了! entity_counter = Counter(entities) top_entities = entity_counter.most_common() # 接下來就開始打印本·拉登提到次數最多的實體吧! for top_entity in top_entities[0:10]: # most_common returns a tuple (entity,count) print("%s => %d" % (top_entity[0], top_entity[1]))
上面函數的最後,我們使用了Counter類來加載entities字典,並且很容易地就得出了最常見的實體。
快速執行腳本
最後執行腳本時,一定要注意:要把腳本放在alchemyapi_python這個文件夾裏。這是因爲AlchemyAPI SDK並沒有在Python的PATH上。
爲了讓大家少複製粘貼,我已經把相關的操作寫在一個bash腳本里。大家下載腳本後修改API KEY即可。
curl https://raw.githubusercontent.com/bingjin/funscripts/master/laden/bld.sh --output bld.sh sh bld.sh
上圖就是正在執行的腳本。想不想看看最終的分析結果?
我直接告訴你們就太沒趣了,大家可以運行腳本自己看,等待的同時可以品嚐一杯咖啡。當然,劇透也是有的:伊斯蘭教先知穆罕默德居然才排第七!
你分析的結果是怎樣的,留言告訴大家本·拉登提到次數最多的三個實體吧!
結語
本文中僅使用了AlchemyAPI的實體提取功能,其他諸如關鍵詞分析、情感分析、圖像分析等功能都沒有涉及。大家可以在本文的基礎上,進一步發揮自己的想象力,看看還能從本·拉登的書架中得到什麼信息。