3種抓取其中數據的方法。首先是正則表達式,然后是流行的BeautifulSoup模塊,最后是強大的lxml模塊。
1 正則表達式
當我們使用正則表達式抓取國家(或地區)面積數據時,首先需要嘗試匹配``元素中的內容,如下所示。
從上述結果中可以看出,多個國家(或地區)屬性都使用了``標簽。如果我們只想抓取國家(或地區)面積,可以只選擇第二個匹配的元素,如下所示。
這個迭代版本看起來更好一些,但是網頁更新還有很多其他方式,同樣可以讓該正則表達式無法滿足。比如,將雙引號變為單引號,`標簽之間添加多余的空格,或是變更area_label`等。下面是嘗試支持這些可能性的改進版本。
雖然該正則表達式更容易適應未來變化,但又存在難以構造、可讀性差的問題。此外,還有很多其他微小的布局變化也會使該正則表達式無法滿足,比如在`標簽里添加title屬性,或者tr、td`元素修改了它們的CSS類或ID。
從本例中可以看出,正則表達式為我們提供了抓取數據的快捷方式,但是該方法過於脆弱,容易在網頁更新后出現問題。幸好,還有更好的數據抽取解決方案,比如我們將在本章介紹的其他抓取庫。
2 Beautiful Soup
Beautiful Soup
是一個非常流行的Python庫,它可以解析網頁,並提供了定位內容的便捷接口。如果你還沒有安裝該模塊,可以使用下面的命令安裝其最新版本。
使用Beautiful Soup的第一步是將已下載的HTML內容解析為soup文檔。由於許多網頁都不具備良好的HTML格式,因此Beautiful Soup需要對其標簽開合狀態進行修正。例如,在下面這個簡單網頁的列表中,存在屬性值兩側引號缺失和標簽未閉合的問題。
如果Population列表項被解析為Area列表項的子元素,而不是並列的兩個列表項的話,我們在抓取時就會得到錯誤的結果。下面讓我們看一下Beautiful Soup是如何處理的。
我們可以看到,使用默認的html.parser並沒有得到正確解析的HTML。從前面的代碼片段可以看出,由於它使用了嵌套的li元素,因此可能會導致定位困難。幸運的是,我們還有其他解析器可以選擇。我們可以安裝LXML(2.2.3節中將會詳細介紹),或使用html5lib。要想安裝html5lib,只需使用pip。
現在,我們可以重復這段代碼,只對解析器做如下變更。
此時,使用了html5lib的BeautifulSoup已經能夠正確解析缺失的屬性引號以及閉合標簽,並且還添加了和標簽,使其成為完整的HTML文檔。當你使用lxml時,也可以看到類似的結果。
現在,我們可以使用find()和find_all()方法來定位我們需要的元素了。
想要了解可用方法和參數的完整列表,請訪問Beautiful Soup的官方文檔。
下面是使用該方法抽取示例網站中國家(或地區)面積數據的完整代碼。
這段代碼雖然比正則表達式的代碼更加復雜,但又更容易構造和理解。而且,像多余的空格和標簽屬性這種布局上的小變化,我們也無須再擔心了。我們還知道即使頁面中包含了不完整的HTML,Beautiful Soup也能幫助我們整理該頁面,從而讓我們可以從非常不完整的網站代碼中抽取數據。
3 Lxml
Lxml
是基於libxml2這一XML解析庫構建的Python庫,它使用C語言編寫,解析速度比Beautiful Soup更快,不過安裝過程也更為復雜,尤其是在Windows中。如果你在自行安裝該庫時遇到困難,也可以使用Anaconda來實現。
你可能對Anaconda不太熟悉,它是由Continuum Analytics公司員工創建的主要專注於開源數據科學包的包和環境管理器。你可以按照其安裝說明下載及安裝Anaconda。需要注意的是,使用Anaconda的快速安裝會將你的PYTHON_PATH設置為Conda的Python安裝位置。
和Beautiful Soup一樣,使用lxml模塊的第一步也是將有可能不合法的HTML解析為統一格式。下面是使用該模塊解析同一個不完整HTML的例子。
同樣地,lxml也可以正確解析屬性兩側缺失的引號,並閉合標簽,不過該模塊沒有額外添加和標簽。這些都不是標准XML的要求,因此對於lxml來說,插入它們並不是必要的。
解析完輸入內容之后,進入選擇元素的步驟,此時lxml有幾種不同的方法,比如XPath選擇器和類似Beautiful Soup的find()方法。不過,在本例中,我們將會使用CSS選擇器,因為它更加簡潔,並且能夠在第5章解析動態內容時得以復用。一些讀者可能由於他們在jQuery選擇器方面的經驗或是前端Web應用開發中的使用對它們已經有所熟悉。在本章的后續部分,我們將對比這些選擇器與XPath的性能。要想使用CSS選擇器,你可能需要先安裝cssselect庫,如下所示。
現在,我們可以使用lxml的CSS選擇器,抽取示例頁面中的面積數據了。
通過對代碼樹使用cssselect方法,我們可以利用CSS語法來選擇表格中ID為places_area__row的行元素,然后是類為w2p_fw的子表格數據標簽。由於cssselect返回的是一個列表,我們需要獲取其中的第一個結果,並調用text_content方法,以迭代所有子元素並返回每個元素的相關文本。