一、前言
通過前面的文章,我們已經(jīng)知道了如何獲取網(wǎng)頁和下載文件,但是前面我們獲取的網(wǎng)頁都是未經(jīng)處理的,冗余的信息太多,無法進行分析和利用
這一節(jié)我們就來學習怎么從網(wǎng)頁中篩選自己需要的信息
說到信息篩選我們立馬就會想到正則表達式,不過今天我們不講正則表達式。因為對于爬蟲來講,正則表達式太復雜對新手十分不友好,而且正則表達式的容錯率差,網(wǎng)頁有稍微的改動就得重新寫匹配表達式,另外正則表達式可讀性幾乎沒有。
當然,這并不是說正則不好,只是正則不適合爬蟲和新手。其實正則是十分強大的,在后面的數(shù)據(jù)清洗里我們會用到正則。
既然正則不能用,那該用什么呢?別擔心,python為我們提供了很多解析 html頁面的庫,其中常用的有:
- bs4中的 BeautifulSoup
- lxml中的 etree(一個 xpath解析庫)
BeautifulSoup類似 jQuery的選擇器,通過 id、css選擇器和標簽來查找元素,xpath主要通過 html節(jié)點的嵌套關系來查找元素,和文件的路徑有點像,比如:
#獲取 id為 tab的 table標簽下所有 tr標簽
path = '//table[@id="tab"]//tr'
#和文件路徑對比
path = 'D:\Github\hexo\source\_posts'
BeautifulSoup和 xpath沒有好壞優(yōu)劣之分,講 xpath是因為個人覺得 xpath更好用一些,后面如果時間允許的話再講 BeautifulSoup。
現(xiàn)在,讓我們先從 xpath開始!
二、xpath的安裝和使用
-
安裝 lxml庫
pip install lxml -
簡單的使用
在使用 xpath之前,先導入 etree類,對原始的 html頁面進行處理獲得一個_Element對象
我們可以通過_Element對象來使用 xpath
#導入 etree類 from lxml import etree #作為示例的 html文本 html = '''<div class="container"> <div class="row"> <div class="col"> <div class="card"> <div class="card-content"> <a href="#123333" class="box"> 點擊我 </a> </div> </div> </div> </div> </div>''' #對 html文本進行處理 獲得一個_Element對象 dom = etree.HTML(html) #獲取 a標簽下的文本 a_text = dom.xpath('//div/div/div/div/div/a/text()') print(a_text)打印結果:
result-1熟悉 html的朋友都知道在 html中所有的標簽都是節(jié)點。一個 html文檔是一個文檔節(jié)點,一個文檔節(jié)點包含一個節(jié)點樹,也叫做 dom樹。
節(jié)點樹中的節(jié)點彼此擁有層級關系。
父(parent)、子(child)和同胞(sibling)等術語用于描述這些關系。父節(jié)點擁有子節(jié)點。同級的子節(jié)點被稱為同胞(兄弟或姐妹)。
- 在節(jié)點樹中,頂端節(jié)點被稱為根(root)
- 每個節(jié)點都有父節(jié)點、除了根(它沒有父節(jié)點)
- 一個節(jié)點可擁有任意數(shù)量的子
- 同胞是擁有相同父節(jié)點的節(jié)點
from w3school:http://www.w3school.com.cn/htmldom/dom_nodes.asp
另外,我們把距離某個節(jié)點最近的子節(jié)點叫做它的直接子節(jié)點,如下圖所示的 body和 head就是 html的直接子節(jié)點
dom樹 w3school了解了 html結構之后我們再來看 xpath的使用。
首先,我們通過 etree.HTML( )來生成一個_Element對象,etree.HTML() 會將傳入的文本處理成一個 html文檔節(jié)點。這樣就能保證我們總是能獲得一個包含文檔節(jié)點的_Element對象。
-
xpath語法
a / b :‘/’在 xpath里表示層級關系,左邊的 a是父節(jié)點,右邊的 b是子節(jié)點,這里的 b是 a的直接子節(jié)點
-
a // b:兩個 / 表示選擇所有 a節(jié)點下的 b節(jié)點(可以是直接子節(jié)點,也可以不是),在上面的例子中我們要選擇 a標簽是這樣寫的
a_text = dom.xpath('//div/div/div/div/div/a/text()') #用 // a_text = dom.xpath('//div//a/text()') #如果 div標簽下有兩個 a標簽,那么這兩個 a標簽都會被選擇(注意兩個 a標簽并不一定是兄弟節(jié)點) #比如下面的例子中的兩個 a標簽都會被選擇 因為這兩個 a標簽都是 div的子節(jié)點 '''<div class="container"> <div class="row"> <div class="col"> <div class="card"> <a href="#123332" class="box"> 點擊我 </a> <div class="card-content"> <a href="#123333" class="box"> 點擊我 </a> </div> </div> </div> </div> </div>''' -
[@]:選擇具有某個屬性的節(jié)點
- //div[@classs], //a[@x]:選擇具有 class屬性的 div節(jié)點、選擇具有 x屬性的 a節(jié)點
- //div[@class="container"]:選擇具有 class屬性的值為 container的 div節(jié)點
//a[contains(text(), "點")]:選擇文本內容里含有 “點” 的 a標簽,比如上面例子中的兩個 a標簽
-
//a[contains(@id, "abc")]:選擇 id屬性里有 abc的 a標簽,如
#這兩條 xpath規(guī)則都可以選取到例子中的兩個 a標簽 path = '//a[contains(@href, "#123")]' path = '//a[contains(@href, "#1233")]' //a[contains(@y, "x")]:選擇有 y屬性且 y屬性包含 x值的 a標簽
總結
- 使用 xpath之前必須先對 html文檔進行處理
- html dom樹中所有的對象都是節(jié)點,包括文本,所以 text()其實就是獲取某個標簽下的文本節(jié)點
- 通過_Element對象的 xpath方法來使用 xpath
- 注意?。?!_Element.xpath( path) 總是返回一個列表
有問題歡迎評論
上一篇:python爬蟲系列之 requests實戰(zhàn):用 requests庫下載網(wǎng)頁和圖片
下一篇:python爬蟲系列之 xpath實戰(zhàn):批量下載壁紙
下一篇實戰(zhàn)我們會用 requests和 xpath寫一個批量下載壁紙的爬蟲

