日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

xpath中两个冒号_爬虫学习(5)—XPath

發(fā)布時(shí)間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 xpath中两个冒号_爬虫学习(5)—XPath 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前我們寫了一個(gè)簡(jiǎn)單的爬蟲,在提取頁面信息時(shí)我們使用正則表達(dá)式來匹配內(nèi)容,但是正則表達(dá)式的書寫比較繁瑣,而且一旦錯(cuò)誤就可能導(dǎo)致匹配失敗。對(duì)于網(wǎng)頁的節(jié)點(diǎn)來說,它可以定義id,class或其他的屬性,而且節(jié)點(diǎn)之間還有層次關(guān)系,在網(wǎng)頁中可以通過xpath后css選擇器來定位一個(gè)或多個(gè)節(jié)點(diǎn)。那么,我們?cè)诮馕鲰撁鏁r(shí),利用CSS和XPath選擇器來定位節(jié)點(diǎn),再調(diào)用相關(guān)方法來獲取其正文內(nèi)容或?qū)傩浴1疚慕榻BXPath。

1.XPath概述

XPath的選擇功能十分強(qiáng)大,提供了100多個(gè)內(nèi)建函數(shù),用于字符串、數(shù)值、時(shí)間的匹配和節(jié)點(diǎn)、序列的處理。

2.XPath常用規(guī)則

nodename 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn) / 從當(dāng)前節(jié)點(diǎn)選取直接子節(jié)點(diǎn) // 從當(dāng)前節(jié)點(diǎn)選取子孫節(jié)點(diǎn) . 選取當(dāng)前節(jié)點(diǎn) .. 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn) @ 選取屬性

這里就是XPath的常用匹配規(guī)則,示例如下:

//title[@lang='eng']

這個(gè)就表示選擇所有名稱為title,同時(shí)屬性lang的值為eng的節(jié)點(diǎn)。

3.準(zhǔn)備工作

安裝好lxml庫。

4.實(shí)例引入

我們來通過實(shí)例來感受一下使用XPath來對(duì)網(wǎng)頁進(jìn)行解析的過程。

from lxml import etreetext = ''' <div> <ul> <li class="item-0"><a-href="link1.html">first item</a></li> <li class="item-1"><a-href="link2.html">second item</a></li> <li class="item-inactive"><a-href="link3.html">third item</a></li> <li class="item-1"><a-href="link4.html">fourth item</a></li> <li class="item-0"><a-href="link5.html">fifth item</a> </ul> </div> ''' html = etree.HTML(text) result = etree.tostring(html) print(result.decode('utf-8'))

這里我們先導(dǎo)入lxml庫的etree模塊,然后聲明一段HTML文本,在調(diào)用HTML類進(jìn)行初始化,這樣就成功構(gòu)造了一個(gè)XPath解析對(duì)象。我們可以注意到HTML文本中最后一個(gè)li節(jié)點(diǎn)是沒有閉合的,但是etree模塊可以自動(dòng)修正HTML 文本。

我們調(diào)用tostring()方法即可輸出修正后的HTML代碼,但是結(jié)果是bytes類型。這里利用decode()方法將其轉(zhuǎn)換為str類型。

我們也可以通過直接讀取文件來進(jìn)行解析。

from lxml import etreehtml = etree.parse('./test.html', etree.HTMLParser()) result = etree.tostring(html) print(result.decode('utf-8'))

其中test.html的內(nèi)容就是上面的HTML代碼。

5.所有節(jié)點(diǎn)

我們一般會(huì)用//開頭的XPath規(guī)則來選取所有符合要求的節(jié)點(diǎn)。

result = html.xpath('//*') print(result)

這里使用*來匹配所有節(jié)點(diǎn),也就是整個(gè)HTML文本中的所有節(jié)點(diǎn)都會(huì)被獲取,返回形式是一個(gè)列表,每個(gè)元素都是Element類型,后面跟著節(jié)點(diǎn)的名稱。

當(dāng)然,此處匹配也可以指定節(jié)點(diǎn)名稱。如果想獲取所有l(wèi)i節(jié)點(diǎn),如下:

result = html.xpath('//li') print(result) print(result[0])

如果我們要取出其中一個(gè)對(duì)象,可以直接用中括號(hào)加索引,如[0]。

6.子節(jié)點(diǎn)

我們通過/或//即可查找元素的子節(jié)點(diǎn)或子孫節(jié)點(diǎn)。假設(shè)我們現(xiàn)在想選擇li節(jié)點(diǎn)的所有直接a節(jié)點(diǎn),可以這樣實(shí)現(xiàn):

result = html.xpath('//li/a')

如果想獲得所有子孫節(jié)點(diǎn),則可使用//。例如,要獲取ul節(jié)點(diǎn)下的所有子孫a節(jié)點(diǎn),可以這樣實(shí)現(xiàn):

result = html.xpath('//ul//a')

/用于獲取直接子節(jié)點(diǎn),//用于獲取子孫節(jié)點(diǎn)。

7.父節(jié)點(diǎn)

我們?cè)谏厦嬷v了如何查找子節(jié)點(diǎn)或子孫節(jié)點(diǎn),那么加入我們知道了子節(jié)點(diǎn),怎么來查找父節(jié)點(diǎn)呢?可以用..來實(shí)現(xiàn)。

比如,我們選中屬性為link4.html的a節(jié)點(diǎn),然后獲取其父節(jié)點(diǎn),然后再獲取其class屬性。

result = html.xpath('//a[@href="link.html"]/../@class')

同時(shí)也可以使用parent::來獲取父節(jié)點(diǎn)。

result = html.xpath('//a[@href="link.html"]/parent::*/@class')

8.屬性匹配

在選取時(shí),我們還可以使用@符號(hào)進(jìn)行屬性過濾。比如,這里如果要選取class為item-0的li節(jié)點(diǎn),可以這樣實(shí)現(xiàn):

result = html.xpath('//li[@class="item-0"]')

這里我們通過加入[@class="item-0"],限制了節(jié)點(diǎn)的class屬性為item-0,而HTML 文本中符合的li節(jié)點(diǎn)有兩個(gè),所以結(jié)果應(yīng)該返回兩個(gè)匹配到的元素。

9.文本獲取

我們使用XPath中的text()方法獲取節(jié)點(diǎn)中的文本,接下來嘗試獲取前面li節(jié)點(diǎn)中的文本。

result = html.xpath('//li[@class="item-0"]/text()')

我們運(yùn)行之后沒有獲取任何文本。這是為什么呢?因?yàn)閄Path中text()前面是/,代表選取直接子節(jié)點(diǎn),很明顯li節(jié)點(diǎn)的直接子節(jié)點(diǎn)都是a節(jié)點(diǎn),文本都是在a節(jié)點(diǎn)內(nèi)部的,所以只匹配到被修正的li節(jié)點(diǎn)內(nèi)部的換行符。因?yàn)樽詣?dòng)修正的li節(jié)點(diǎn)的尾標(biāo)簽換行了。即選中的是這兩個(gè)節(jié)點(diǎn):

<li class="item-0"><a-href="link1.html">first item</a></li> <li class="item-0"><a-href="link5.html">fifth item</a> </li>

因此,如果想獲取li節(jié)點(diǎn)內(nèi)部的文本,就有兩種方式:一種是先選取a節(jié)點(diǎn)再獲取文本,另一種是使用//。

result = html.xpath('//li[@class="item-0"]/a/text()')

運(yùn)行結(jié)果為:

['first item', 'fifth item']

這里我們是逐層選取,先選取了li節(jié)點(diǎn),又利用/選取了其直接子節(jié)點(diǎn)a。

result = html.xpath('//li[@class="item-0"]//text()')

運(yùn)行結(jié)果為:

['first item', 'fifth item', 'n ']

這里是選取所有子孫節(jié)點(diǎn)的文本,其中兩個(gè)是li的子節(jié)點(diǎn)a節(jié)點(diǎn)內(nèi)部的文本,另外一個(gè)就是最后一個(gè)li節(jié)點(diǎn)內(nèi)部的文本,即換行符。

10.屬性獲取

我們使用text()方法獲取文本內(nèi)容,我們也可以用@href來獲取節(jié)點(diǎn)的href屬性。

result = html.xpath('//li/a/@href')

11.屬性多值匹配

有時(shí)候,某些節(jié)點(diǎn)的某個(gè)屬性有多個(gè)值,例如:

from lxml import etreetext = ''' <li class="li li-first"><a href="link.html">first item</a></li> ''' html = etree.HTML(text) result = html.xpath('//li[@class="li"]/a/text()') print(result)

這里返回的結(jié)果是[],因?yàn)閘i的class屬性有兩個(gè)值li和li-first,此時(shí)還想用之前的屬性匹配獲取就無法匹配了。

這時(shí)就需要用contains()函數(shù)了,代碼如下:

result = html.xpath('//li[contains(@class, "li")]/a/text()')

這樣就會(huì)得到結(jié)果['first item']。

12.多屬性匹配

另外,我們還會(huì)碰到另一種情況,那就是依據(jù)多個(gè)屬性來確定一個(gè)節(jié)點(diǎn),這時(shí)就需要同時(shí)匹配多個(gè)屬性,此時(shí)我們可以使用運(yùn)算符and來連接。

from lxml import etreetext = ''' <li class="li li-first" name="item"><a href="link.html">first item</a></li> ''' html = etree.HTML(text) result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()') print(result)

這里的li節(jié)點(diǎn)又增加了一個(gè)屬性name。要確定這個(gè)節(jié)點(diǎn),需要用時(shí)根據(jù)class和name來選擇,中間用and相連,相連之后置于中括號(hào)內(nèi)進(jìn)行條件篩選。除了and之外還有其他的運(yùn)算符可以使用。

13.順序選擇

我們?cè)谶x擇的時(shí)候某些屬性可能已經(jīng)匹配了多個(gè)節(jié)點(diǎn),但是我們只想要其中的某個(gè)節(jié)點(diǎn),如第二個(gè)節(jié)點(diǎn)或者最后一個(gè)節(jié)點(diǎn)。

from lxml import etreetext = ''' <div> <ul> <li class="item-0"><a-href="link1.html">first item</a></li> <li class="item-1"><a-href="link2.html">second item</a></li> <li class="item-inactive"><a-href="link3.html">third item</a></li> <li class="item-1"><a-href="link4.html">fourth item</a></li> <li class="item-0"><a-href="link5.html">fifth item</a> </ul> </div> ''' html = etree.HTML(text) result = html.xpath('//li[1]/a/text()') print(result) result = html.xpath('//li[last()]/a/text()') print(result) result = html.xpath('//li[position()<3]/a/text()') print(result) result = html.xpath('//li[last()-2]/a/text()') print(result)

第一次選擇時(shí),我們選取了第一個(gè)li節(jié)點(diǎn),這里在中括號(hào)中傳入1就可。

第二次選擇時(shí),我們選取最后一個(gè)li節(jié)點(diǎn),中括號(hào)中傳入last()即可。

第三次選擇時(shí),我們選取了位置小于3的li節(jié)點(diǎn),運(yùn)用了position()函數(shù)。

第四次選擇時(shí),我們選擇了都輸?shù)谌齻€(gè)li節(jié)點(diǎn),中括號(hào)中傳入last()-2即可。

在Xpath中,提供了100多個(gè)函數(shù),包括存取、數(shù)值、字符串、邏輯、節(jié)點(diǎn)、序列等的處理功能。

14.節(jié)點(diǎn)軸選擇

XPath提供了許多節(jié)點(diǎn)軸選擇方法,包括獲取子元素、兄弟元素、父元素、祖先元素等,示例如下:

from lxml import etreetext = ''' <div> <ul> <li class="item-0"><a-href="link1.html">first item</a></li> <li class="item-1"><a-href="link2.html">second item</a></li> <li class="item-inactive"><a-href="link3.html">third item</a></li> <li class="item-1"><a-href="link4.html">fourth item</a></li> <li class="item-0"><a-href="link5.html">fifth item</a> </ul> </div> ''' html = etree.HTML(text) result = html.xpath('//li[1]/ancestor::*') print(result) result = html.xpath('//li[1]/ancestor::div') print(result) result = html.xpath('//li[1]/attribute::*') print(result) result = html.xpath('//li[1]/child::a[@href="link1.html"]') print(result) result = html.xpath('//li[1]/descendant::span') print(result) result = html.xpath('//li[1]/following::*[2]') print(result) result = html.xpath('//li[1]/following-sibling::*') print(result)

第一次選擇時(shí),我們調(diào)用了ancestor軸,可以獲取所有的祖先節(jié)點(diǎn)。之后需要跟兩個(gè)冒號(hào),然后是節(jié)點(diǎn)的選擇器,這里我們使用*,表示匹配所有節(jié)點(diǎn)。

第二次選擇時(shí),我們又加了限定條件div,這時(shí)得到的結(jié)果就只有div這個(gè)祖先節(jié)點(diǎn)了。

第三次選擇時(shí),我們調(diào)用了attribute軸,可以獲取所有屬性值,其建甌跟的選擇器還是*,代表獲取節(jié)點(diǎn)的所有屬性。

第四次選擇時(shí),我們調(diào)用了child軸,可以獲取所有直接子節(jié)點(diǎn)。這里我們又加入了限定條件,選取href屬性為link1.html的a節(jié)點(diǎn)。

第五次選擇時(shí),我們調(diào)用了descendant軸,可以獲取所有的子孫節(jié)點(diǎn)。這里我們又加入了限制條件獲取span節(jié)點(diǎn)。所以返回的結(jié)果只包含span節(jié)點(diǎn)而不包括a節(jié)點(diǎn)。

第六次選擇時(shí),我們調(diào)用了following軸,可以獲取當(dāng)前節(jié)點(diǎn)之后的所有節(jié)點(diǎn)。這里我們使用*匹配,但又加入了索引選擇,所以只獲取了第二個(gè)后續(xù)節(jié)點(diǎn)。

第七次選擇時(shí),我們調(diào)用了following-sibling軸,可以獲取當(dāng)前節(jié)點(diǎn)之后的所有同級(jí)節(jié)點(diǎn)。這里我們使用*匹配,獲取所有后續(xù)同級(jí)節(jié)點(diǎn)。

參考書目:《Python 3 網(wǎng)絡(luò)爬蟲開發(fā)實(shí)戰(zhàn)》

總結(jié)

以上是生活随笔為你收集整理的xpath中两个冒号_爬虫学习(5)—XPath的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。