[译] Web 爬虫下的 Python 数据分析:中情局全球概况图解
- 原文地址:Data Analytics with Python by Web scraping: Illustration with CIA World Factbook
- 原文作者:Tirthajyoti Sarkar
- 譯文出自:掘金翻譯計劃
- 本文永久鏈接:github.com/xitu/gold-m…
- 譯者:Starrier
- 校對者:allenlongbaobao、FateZeros
Web 爬蟲下的 Python 數據分析:中情局全球概況圖解
在本文章中,我將展示如何使用 Python 和 HTML 解析從網頁中獲取有價值的信息,之后會回答一些重要的數據分析問題。
在數據科學項目中,數據采集和清洗幾乎總是最耗時、最麻煩的步驟。每個人都喜歡用 3D 交互式圖表來構建一兩個很酷的深度神經網絡(或者 XGboost)模型,以此炫耀個人的技術。但這些模型是需要原始數據的,而且它們并不容易采集和清洗。
畢竟生活不像 Kaggle 一樣是一個 zip 格式文件,等待您的解壓和建模 :-)
但為什么我們要采集數據或者構建模型呢?最初的動機是回答商業、科學或者是社會上的問題。這是趨勢么?事物間的關聯性?實體的測量可以預測出這種現象的結果么?因為回答這個問題將會驗證您作為這個該領域的科學家/實踐者所提出的假設。您只是在使用數據(而不是像化學家使用試管或者物理學家使用磁鐵)來驗證您的假設,并且科學地證明/反駁它。這就是數據科學中的「科學」部分,名副其實……
相信我,提出一個需要一些數據科學技術應用來解決的高質量問題并不難。而且每一個這樣的問題都會成為您的一個小項目,您可以將它開源在 Gihub 這樣的平臺來和您的朋友們分享。即使您不是專業的數據專家,也沒有人可以阻止您通過編寫很酷的代碼來回答一個高質量的數據問題。這也表明您是對數據敏感并且可以用數據講故事的人。
今天讓我們來解決這樣一個問題。。。
一個國家的 GDP(按購買力平價)與其互聯網用戶比例是否有任何關系?這種趨勢對于低收入/中等收入/高收入國家而言是否類似?
現在您可以想到許多原始資料可以采集來作為回答此問題的數據。我發現中情局(是的 ‘AGENCY’)的一個網站保存了世界上所有國家的基本事實信息,是一個采集數據的好地方。
因此我們將使用以下 Python 模塊來構建我們的數據庫和可視化,
- Pandas, Numpy, matplotlib/seaborn
- Python urllib (發送 HTTP 請求)
- BeautifulSoup (用于 HTML 解析)
- Regular expression module (用于查找要搜索的精確匹配文本)
讓我們討論一下解決這個數據科學問題的程序結構。整個項目代碼在我的 Github 倉庫中都可以找到。如果您喜歡的話,請 fork 或者給個 star。
閱讀 HTML 首頁并傳遞給 BeautifulSoup
這兒是中情局全球概況首頁
圖:中情局全球概況首頁
我們使用一個帶有 SSL 錯誤忽略上下文的簡單 urllib 請求來檢索這個頁面,然后將它傳遞給神奇的 BeautifulSoup,它將為我們解析 HTML 并生成一個漂亮的文本轉儲。對于那些不熟悉 BeautifulSoup 庫的人,他們可以觀以下視頻或者在 Medium 上閱讀這篇內容豐富的文章。
YouTube 視頻地址:https://youtu.be/aIPqt-OdmS0
以下是讀取的首頁 HTML 的代碼片段,
ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE# 從 URL 中讀取 HTML 并將其傳遞給 BeautifulSoup url = 'https://www.cia.gov/library/publications/the-world-factbook/' print("Opening the file connection...") uh= urllib.request.urlopen(url, context=ctx) print("HTTP status",uh.getcode()) html =uh.read().decode() print(f"Reading done. Total {len(html)} characters read.") 復制代碼以下是我們如何將其傳遞給 BeautifulSoup 并使用 find_all 方法查找 HTML 中嵌入的所有國家名稱和代碼。基本上,這個想法是找到名為 ‘option’ 的 HTML 標簽。標簽中的文本是國家名,標簽值的 5 號和 6 號表示的是 2 個字符的國家代碼。
現在您可能會問,您如何知道只需要提取第五和第六字符?簡單的答案是您必須親自檢查 soup 文本--即解析的 HTML 文本,并確定這些索引。沒有通用的方法來檢查這一點,因為每個 HTML 頁面和底層結構都是獨一無二的。
soup = BeautifulSoup(html, 'html.parser') country_codes=[] country_names=[]for tag in soup.find_all('option'):country_codes.append(tag.get('value')[5:7])country_names.append(tag.text)temp=country_codes.pop(0) # To remove the first entry 'World' temp=country_names.pop(0) # To remove the first entry 'World' 復制代碼爬取:將所有國家的文本數據逐個抓取到字典中
這一步就是他們所說的爬取或者抓取。要實現這一點,關鍵是要確定每個國家信息頁面的 URL 是如何構造的。現在的一般情況是,這將很難獲得。特殊情況下,快速檢查顯示了一個非常簡單并且有規律的結構,以澳大利亞截圖為例。
這意味著有一個固定的URL,您必須附加兩個字符的國家代碼,并獲得該國家的頁面網址。因此,我們只需遍歷國家代碼列表,使用 BeautifulSoup 提取所有文本并存儲在本地詞典中。這是代碼片,
# 基礎 URL urlbase = 'https://www.cia.gov/library/publications/the-world-factbook/geos/' # 空數據字典 text_data=dict()# 遍歷每個國家 for i in range(1,len(country_names)-1):country_html=country_codes[i]+'.html'url_to_get=urlbase+country_html# 從 URL 中讀取 HTML 并將其傳遞給 BeautifulSouphtml = urllib.request.urlopen(url_to_get, context=ctx).read()soup = BeautifulSoup(html, 'html.parser')txt=soup.get_text()text_data[country_names[i]]=txtprint(f"Finished loading data for {country_names[i]}")print ("\n**Finished downloading all text data!**") 復制代碼如果您喜歡,可以存放在一個 Pickle dump 中
另外,我偏向于序列化并將數據存儲在Python pickle 對象中。這樣我下次打開 Jupyter 筆記本時,就可以直接讀取數據而無需重復網絡爬行步驟。
import pickle pickle.dump(text_data,open("text_data_CIA_Factobook.p", "wb"))# 取消選擇,下次從本地存儲區讀取數據。 text_data = pickle.load(open("text_data_CIA_Factobook.p", "rb")) 復制代碼使用正則表達式從文本轉儲中提取 GDP/人均數據
這是程序的核心文本分析部分,我們借助正則表達式模塊來查找我們在龐大文本字符串中尋找的內容,并提取相關的數字數據。現在,正則表達式是 Python(或者幾乎是所有的高級編程語言)中的一個豐富資源。它允許在大量文本中以特定模式搜索/匹配字符串。這里我們使用非常簡單的正則表達式方法來匹配精確的單詞,如“GDP?—?per capita (PPP):”然后讀取幾個字符,提取諸如 $ 和 () 等特定符號的位置,最后提取 GDP/人均數值。這是一個用數字說明的想法。
圖:文本分析圖示。
這個筆記本中還有其他一些常用的表達方式,例如,不管這個數字是以數十億還是數萬億美元計算出來的,都可以正確地提取出 GDP 總量。
# 'b' 去捕捉 'billions', 't' 去捕捉 'trillions' start = re.search('\$',string) end = re.search('[b,t]',string) if (start!=None and end!=None):start=start.start()end=end.start()a=string[start+1:start+end-1]a = convert_float(a)if (string[end]=='t'):# 如果 GDP 數值在 萬億中,則乘以 1000a=1000*a 復制代碼以下是代碼片段的示例。注意放置在代碼中的多個錯誤處理檢查。這是必要的,因為 HTML 頁面具有極不可預測性。并非所有國家都有 GDP 數據,并非所有頁面的數據措辭都完全相同,并非所有數字看起來都一樣,并非所有字符串放置方式都類似于 $ 和 ()。任何事都可能出錯。
為所有的場景規劃和編寫代碼幾乎是不可能,但至少要有代碼來處理可能出現的異常,這樣您的程序才不會停止,并且可以繼續優雅地進行下一頁處理。
# 初始化保存數據的字典 GDP_PPP = {} # 遍歷每個國家 for i in range(1,len(country_names)-1):country= country_names[i]txt=text_data[country] pos = txt.find('GDP - per capita (PPP):')if pos!=-1: #If the wording/phrase is not presentpos= pos+len('GDP - per capita (PPP):')string = txt[pos+1:pos+11]start = re.search('\$',string)end = re.search('\S',string)if (start!=None and end!=None): #If search fails somehowstart=start.start()end=end.start()a=string[start+1:start+end-1]#print(a)a = convert_float(a)if (a!=-1.0): #If the float conversion fails somehowprint(f"GDP/capita (PPP) of {country}: {a} dollars")# 在字典中插入數據GDP_PPP[country]=aelse:print("**Could not find GDP/capita data!**")else:print("**Could not find GDP/capita data!**")else:print("**Could not find GDP/capita data!**") print ("\nFinished finding all GDP/capita data") 復制代碼不要忘記使用 pandas inner/left join 方法
需要記住的一點是,所有這些分本分析都將產生具有略微不同的國家集的數據。因為不同的國家可能無法獲得不同類型的數據。人們可以使用一個 Pandas left join 來創建一個與所有可獲得/可以提取的所有數據片段的所有公共國家相交的數據。
df_combined = df_demo.join(df_GDP, how='left') df_combined.dropna(inplace=True) 復制代碼啊,現在是很酷的東西,建模。。。但等等!還是先過濾吧!
在完成了所有的 HTML 解析、頁面爬取和文本挖掘后,現在您已經可以享受這些好處了--渴望運行回歸算法和很酷的可視化腳本!但是等等,在生成這些東西之前,通常您需要清洗您的數據(特別是針對這種社會經濟問題)。基本上,您需要過濾掉異常值,例如非常小的國家(比如島嶼國家),它們可能對您要繪制的參數值造成極大的偏差,且不遵循您想要研究的主要基本動態。對這些過濾器來說,幾行代碼是很好的。可能有更多的 Pythonic 方法來實現他們,但我盡量保持它極其簡單且易于遵循。例如,下面的代碼創建過濾器,將 GDP 小于五百億的小國拒之門外,低收入和高收入的界限分別為 5000 美元和 25000 美元(GDP/人均 GDP)。
# 創建過濾后的數據幀、x 和 y 數組 filter_gdp = df_combined['Total GDP (PPP)'] > 50 filter_low_income=df_combined['GDP (PPP)']>5000 filter_high_income=df_combined['GDP (PPP)']<25000df_filtered = df_combined[filter_gdp][filter_low_income][filter_high_income] 復制代碼最后是可視化
我們使用 seaborn regplot 函數創建線性回歸擬合的散點圖(互聯網用戶數量比上人均 GDP)和顯示 95% 置信區間帶。他們看起來就像下面一樣。可以將結果解釋為
一個國家的互聯網用戶數量與人均 GDP 之間存在著很強的正相關關系。此外,低收入/低 GDP 國家的相關強度明顯高于高 GDP 發達國家。這可能意味著,與發達國家相比,互聯網接入有助于低收入國家更快地增長,并更好地改善其公民的平均狀況。
總結
本文通過一個 Python 筆記本演示來說明如何通過使用 BeautifulSoup 進行 HTML 解析來抓取用于下載原始信息的網頁。在此基礎上,闡述了如何利用正則表達式模塊來搜索和提取用戶所需要的重要信息。
最重要的是,它演示了在挖掘雜亂的HTML解析文本時,如何或為什么不可能有簡單、通用的規則或程序結構。我們必須檢查文本結構,并設置適當的錯誤處理檢查,以便恰當地處理所有情況,以維護程序的流程(而不是崩潰),即使它無法提取所有這些場景的數據。
我希望讀者能從提供的筆記本文件中獲益,并根據自己的需求和想象力在此基礎上構建。更多 Web 數據分析筆記 請查看我的倉庫
如果您有任何問題和想法可以分享,請聯系作者 tirthajyoti@gmail.com。當然您也可以查看作者的 GitHub 倉庫中的 Python, R, 或者 MATLAB 和機器學習的資源。如果你像我一樣熱衷于機器學習/數據科學,請隨時在 LinkedIn 上添加我或者在 Twitter 上關注我。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、后端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。
總結
以上是生活随笔為你收集整理的[译] Web 爬虫下的 Python 数据分析:中情局全球概况图解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: so加载报错:dlopen failed
- 下一篇: 解决Intellij IDEA部署Jav