Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
文主要圍繞以xpath和lxml庫進(jìn)行展開:
一、xpath 概念、xpath節(jié)點(diǎn)、xpath語法、xpath軸、xpath運(yùn)算符
二、lxml的安裝、lxml的使用、lxml案例
一、xpath
1.xpath概念
XPath 是一門在 XML 文檔中查找信息的語言。XPath 使用路徑表達(dá)式在 XML 文檔中進(jìn)行導(dǎo)航 。XPath 包含一個(gè)標(biāo)準(zhǔn)函數(shù)庫 。XPath 是 XSLT 中的主要元素 。XPath 是一個(gè) W3C 標(biāo)準(zhǔn) 。
2.xpath節(jié)點(diǎn)
xpath有七種類型的節(jié)點(diǎn):元素、屬性、文本、命名空間、處理指令、注釋以及文檔(根)節(jié)點(diǎn)。
節(jié)點(diǎn)關(guān)系:父、子、兄弟、先輩、后輩。
3.xpath語法
xpath語法在W3c網(wǎng)站上有詳細(xì)的介紹,這里截取部分知識(shí),供大家學(xué)習(xí)。
XPath 使用路徑表達(dá)式在 XML 文檔中選取節(jié)點(diǎn)。節(jié)點(diǎn)是通過沿著路徑或者 step 來選取的。下面列出了最有用的路徑表達(dá)式:
表達(dá)式 | 描述 |
nodename | 選取此節(jié)點(diǎn)的所有子節(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)。 |
@ | 選取屬性。 |
在下面的表格中,我們已列出了一些路徑表達(dá)式以及表達(dá)式的結(jié)果:
路徑表達(dá)式 | 結(jié)果 |
bookstore | 選取 bookstore 元素的所有子節(jié)點(diǎn)。 |
/bookstore | 選取根元素 bookstore。注釋:假如路徑起始于正斜杠( / ),則此路徑始終代表到某元素的絕對(duì)路徑! |
bookstore/book | 選取屬于 bookstore 的子元素的所有 book 元素。 |
//book | 選取所有 book 子元素,而不管它們?cè)谖臋n中的位置。 |
bookstore//book | 選擇屬于 bookstore 元素的后代的所有 book 元素,而不管它們位于 bookstore 之下的什么位置。 |
//@lang | 選取名為 lang 的所有屬性。 |
謂語用來查找某個(gè)特定的節(jié)點(diǎn)或者包含某個(gè)指定的值的節(jié)點(diǎn)。
謂語被嵌在方括號(hào)中。
在下面的表格中,我們列出了帶有謂語的一些路徑表達(dá)式,以及表達(dá)式的結(jié)果:
路徑表達(dá)式 | 結(jié)果 |
/bookstore/book[1] | 選取屬于 bookstore 子元素的第一個(gè) book 元素。 |
/bookstore/book[last()] | 選取屬于 bookstore 子元素的最后一個(gè) book 元素。 |
/bookstore/book[last()-1] | 選取屬于 bookstore 子元素的倒數(shù)第二個(gè) book 元素。 |
/bookstore/book[position()<3] | 選取最前面的兩個(gè)屬于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 選取所有擁有名為 lang 的屬性的 title 元素。 |
//title[@lang='eng'] | 選取所有 title 元素,且這些元素?fù)碛兄禐?eng 的 lang 屬性。 |
/bookstore/book[price>35.00] | 選取 bookstore 元素的所有 book 元素,且其中的 price 元素的值須大于 35.00。 |
/bookstore/book[price>35.00]/title | 選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大于 35.00。 |
XPath 通配符可用來選取未知的 XML 元素。
通配符 | 描述 |
* | 匹配任何元素節(jié)點(diǎn)。 |
@* | 匹配任何屬性節(jié)點(diǎn)。 |
node() | 匹配任何類型的節(jié)點(diǎn)。 |
在下面的表格中,我們列出了一些路徑表達(dá)式,以及這些表達(dá)式的結(jié)果:
路徑表達(dá)式 | 結(jié)果 |
/bookstore/* | 選取 bookstore 元素的所有子元素。 |
//* | 選取文檔中的所有元素。 |
//title[@*] | 選取所有帶有屬性的 title 元素。 |
通過在路徑表達(dá)式中使用"|"運(yùn)算符,您可以選取若干個(gè)路徑。
在下面的表格中,我們列出了一些路徑表達(dá)式,以及這些表達(dá)式的結(jié)果:
路徑表達(dá)式 | 結(jié)果 |
//book/title | //book/price | 選取 book 元素的所有 title 和 price 元素。 |
//title | //price | 選取文檔中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 選取屬于 bookstore 元素的 book 元素的所有 title 元素,以及文檔中所有的 price 元素。 |
4.xpath 軸
軸可定義相對(duì)于當(dāng)前節(jié)點(diǎn)的節(jié)點(diǎn)集。
軸名稱 | 結(jié)果 |
ancestor | 選取當(dāng)前節(jié)點(diǎn)的所有先輩(父、祖父等)。 |
ancestor-or-self | 選取當(dāng)前節(jié)點(diǎn)的所有先輩(父、祖父等)以及當(dāng)前節(jié)點(diǎn)本身。 |
attribute | 選取當(dāng)前節(jié)點(diǎn)的所有屬性。 |
child | 選取當(dāng)前節(jié)點(diǎn)的所有子元素。 |
descendant | 選取當(dāng)前節(jié)點(diǎn)的所有后代元素(子、孫等)。 |
descendant-or-self | 選取當(dāng)前節(jié)點(diǎn)的所有后代元素(子、孫等)以及當(dāng)前節(jié)點(diǎn)本身。 |
following | 選取文檔中當(dāng)前節(jié)點(diǎn)的結(jié)束標(biāo)簽之后的所有節(jié)點(diǎn)。 |
namespace | 選取當(dāng)前節(jié)點(diǎn)的所有命名空間節(jié)點(diǎn)。 |
parent | 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。 |
preceding | 選取文檔中當(dāng)前節(jié)點(diǎn)的開始標(biāo)簽之前的所有節(jié)點(diǎn)。 |
preceding-sibling | 選取當(dāng)前節(jié)點(diǎn)之前的所有同級(jí)節(jié)點(diǎn)。 |
self | 選取當(dāng)前節(jié)點(diǎn)。 |
5.xpath運(yùn)算符
下面列出了可用在 XPath 表達(dá)式中的運(yùn)算符:
運(yùn)算符 | 描述 | 實(shí)例 | 返回值 |
| | 計(jì)算兩個(gè)節(jié)點(diǎn)集 | //book | //cd | 返回所有擁有 book 和 cd 元素的節(jié)點(diǎn)集 |
+ | 加法 | 6 + 4 | 10 |
- | 減法 | 6 - 4 | 2 |
* | 乘法 | 6 * 4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | price=9.80 | 如果 price 是 9.80,則返回 true。如果 price 是 9.90,則返回 false。 |
!= | 不等于 | price!=9.80 | 如果 price 是 9.90,則返回 true。如果 price 是 9.80,則返回 false。 |
< | 小于 | price<9.80 | 如果 price 是 9.00,則返回 true。如果 price 是 9.90,則返回 false。 |
<= | 小于或等于 | price<=9.80 | 如果 price 是 9.00,則返回 true。如果 price 是 9.90,則返回 false。 |
> | 大于 | price>9.80 | 如果 price 是 9.90,則返回 true。如果 price 是 9.80,則返回 false。 |
>= | 大于或等于 | price>=9.80 | 如果 price 是 9.90,則返回 true。如果 price 是 9.70,則返回 false。 |
or | 或 | price=9.80 or price=9.70 | 如果 price 是 9.80,則返回 true。如果 price 是 9.50,則返回 false。 |
and | 與 | price>9.00 and price<9.90 | 如果 price 是 9.80,則返回 true。如果 price 是 8.50,則返回 false。 |
mod | 計(jì)算除法的余數(shù) | 5 mod 2 | 1 |
好了,xpath的內(nèi)容就這么多了。接下來我們要介紹一個(gè)神器lxml,他的速度很快,曾經(jīng)一直是我使用beautifulsoup時(shí)最鐘愛的解析器,沒有之一,因?yàn)樗乃俣鹊拇_比其他的html.parser 和html5lib快了許多。
二、lxml
1.lxml安裝
lxml 是一個(gè)xpath格式解析模塊,安裝很方便,直接pip install lxml 或者easy_install lxml即可。
2.lxml 使用
lxml提供了兩種解析網(wǎng)頁的方式,一種是你解析自己寫的離線網(wǎng)頁時(shí),另一種 則是解析線上網(wǎng)頁。
導(dǎo)入包:
from lxml import etree
1.解析離線網(wǎng)頁:
html=etree.parse('xx.html',etree.HTMLParser())
aa=html.xpath('//*[@id="s_xmancard_news"]/div/div[2]/div/div[1]/h2/a[1]/@href')
print(aa)
2.解析在線網(wǎng)頁:
from lxml import etree
import requests
rep=requests.get('https://www.baidu.com')
html=etree.HTML(rep.text)
aa=html.xpath('//*[@id="s_xmancard_news"]/div/div[2]/div/div[1]/h2/a[1]/@href')
print(aa)
那么我們?cè)趺传@取這些標(biāo)簽和標(biāo)簽對(duì)應(yīng)的屬性值了,很簡單,首先獲取標(biāo)簽只需你這樣做:
然后我們可以,比方說,你要獲取a標(biāo)簽內(nèi)的文本和它的屬性href所對(duì)應(yīng)的值,有兩種方法,
1.表達(dá)式內(nèi)獲取
aa=html.xpath('//*[@id="s_xmancard_news"]/div/div[2]/div/div[1]/h2/a[1]/text()')
ab=html.xpath('//*[@id="s_xmancard_news"]/div/div[2]/div/div[1]/h2/a[1]/@href')
2.表達(dá)式外獲取
aa=html.xpath('//*[@id="s_xmancard_news"]/div/div[2]/div/div[1]/h2/a[1]')
aa.text
aa.attrib.get('href')
這樣就完成了獲取,怎么樣,是不是很簡單了,哈哈哈。
下面再來lxml的解析規(guī)則:
表達(dá)式 | 描述 |
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) |
@ | 選取屬性 |
html=lxml.etree.HTML(text)
#使用text構(gòu)造一個(gè)XPath解析對(duì)象,etree模塊可以自動(dòng)修正HTML文本
html=lxml.etree.parse('./ex.html',etree.HTMLParser())
#直接讀取文本進(jìn)行解析
from lxml import etree
result=html.xpath('//*')
#選取所有節(jié)點(diǎn)
result=html.xpath('//li')
#獲取所有l(wèi)i節(jié)點(diǎn)
result=html.xpath('//li/a')
#獲取所有l(wèi)i節(jié)點(diǎn)的直接a子節(jié)點(diǎn)
result=html.xpath('//li//a')
#獲取所有l(wèi)i節(jié)點(diǎn)的所有a子孫節(jié)點(diǎn)
result=html.xpath('//a[@href="link.html"]/../@class')
#獲取所有href屬性為link.html的a節(jié)點(diǎn)的父節(jié)點(diǎn)的class屬性
result=html.xpath('//li[@class="ni"]')
#獲取所有class屬性為ni的li節(jié)點(diǎn)
result=html.xpath('//li/text()')
#獲取所有l(wèi)i節(jié)點(diǎn)的文本
result=html.xpath('//li/a/@href')
#獲取所有l(wèi)i節(jié)點(diǎn)的a節(jié)點(diǎn)的href屬性
result=html.xpath('//li[contains(@class,"li")]/a/text())
#當(dāng)li的class屬性有多個(gè)值時(shí),需用contains函數(shù)完成匹配
result=html.xpath('//li[contains(@class,"li") and @name="item"]/a/text()')
#多屬性匹配
result=html.xpath('//li[1]/a/text()')
result=html.xpath('//li[last()]/a/text()')
result=html.xpath('//li[position()<3]/a/text()')
result=html.xpath('//li[last()-2]/a/text()')
#按序選擇,中括號(hào)內(nèi)為XPath提供的函數(shù)
result=html.xpath('//li[1]/ancestor::*')
#獲取祖先節(jié)點(diǎn)
result=html.xpath('//li[1]/ancestor::div')
result=html.xpath('//li[1]/attribute::*')
#獲取屬性值
result=html.xpath('//li[1]/child::a[@href="link1.html"]')
#獲取直接子節(jié)點(diǎn)
result=html.xpath('//li[1]/descendant::span')
#獲取所有子孫節(jié)點(diǎn)
result=html.xpath('//li[1]/following::*[2]')
#獲取當(dāng)前節(jié)點(diǎn)之后的所有節(jié)點(diǎn)的第二個(gè)
result=html.xpath('//li[1]/following-sibling::*')
#獲取后續(xù)所有同級(jí)節(jié)點(diǎn)
3.lxml案例
為了偷懶,小編決定還是采用urllib那篇文章的代碼,哈哈哈,機(jī)智如我。
好了,今天就講這么多,大家感興趣的話可以多多關(guān)注哦,精彩不停息!!!!
本文參考文獻(xiàn):
https://www.w3school.com.cn/
想學(xué)習(xí)更多前端、Python爬蟲、大數(shù)據(jù)等計(jì)算機(jī)知識(shí),請(qǐng)前往:http://pdcfighting.com/
XPath 全稱為 Xml Path Language,即 Xml 路徑語言,是一種在 Xml 文檔中查找信息的語言。它提供了非常簡潔的路徑選擇表達(dá)式,幾乎所有的節(jié)點(diǎn)定位都可以用它來選擇。
XPath 可以用于 Xml 和 Html,在爬蟲中經(jīng)常使用 XPath 獲取 Html 文檔內(nèi)容。
lxml 是 Python 語言用 Xpath 解析 XML、Html文檔功能最豐富的、最容易的功能模塊。
在 XPath 中有七種節(jié)點(diǎn)分別是元素、屬性、文本、文檔、命名空間、處理指令、注釋,前3種節(jié)點(diǎn)為常用節(jié)點(diǎn)
請(qǐng)看下面的 Html 例子,(注:這個(gè)例子全文都需要使用)
<!DOCTYPE html>
<html>
<body>
<div>
<!-- 這里是注釋 -->
<h4>手機(jī)品牌商<span style="margin-left:10px">4</span></h4>
<ul>
<li>小米</li>
<li>華為</li>
<li class='blank'> OPPO </li>
<li>蘋果</li>
</ul>
</div>
<div>
<h4>電腦品牌商<span style="margin-left:10px">3</span></h4>
<ul class="ul" style="color:red">
<li>戴爾</li>
<li>機(jī)械革命</li>
<li>ThinkPad</li>
</ul>
</div>
</body>
</html>
在上面的例子中
<html> 為文檔節(jié)點(diǎn)
<li>小米</li> 為元素節(jié)點(diǎn)
class='blank' 為屬性節(jié)點(diǎn)
<!-- 這里是注釋 --> 為注釋節(jié)點(diǎn)
在 XPath中有多中節(jié)點(diǎn)關(guān)系分別是父節(jié)點(diǎn)、子節(jié)點(diǎn)、同胞節(jié)點(diǎn)、先輩節(jié)點(diǎn)、后代節(jié)點(diǎn)
在上面的例子中
表達(dá)式描述nodeName選擇nodeName節(jié)點(diǎn)的所有子節(jié)點(diǎn)/從根節(jié)點(diǎn)開始//從匹配的節(jié)點(diǎn)開始選擇節(jié)點(diǎn).選擇當(dāng)前節(jié)點(diǎn)..選擇當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)@選擇元素*匹配任意元素節(jié)點(diǎn)@*匹配任意屬性節(jié)點(diǎn)
用上面的 Html 文檔舉個(gè)例子
路徑表達(dá)式描述body選取 body 的所有子節(jié)點(diǎn)/html選取 html 節(jié)點(diǎn)//div選取所有 div 節(jié)點(diǎn)//div/./h4div 節(jié)點(diǎn)下的 h4 節(jié)點(diǎn)../div選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)下的所有 div 節(jié)點(diǎn)//@class所有帶有 class 元素的節(jié)點(diǎn)//*選擇所有節(jié)點(diǎn)//@*選擇所有屬性節(jié)點(diǎn)
表達(dá)式描述position()返回節(jié)點(diǎn)的 index 位置last()返回節(jié)點(diǎn)的個(gè)數(shù)contains(string1,string2)string1 是否包含 string2text()返回文本節(jié)點(diǎn)comment()返回注釋節(jié)點(diǎn)normalize-space(string)去除首位空格,中間多個(gè)空格用一個(gè)空格代替substring(string,start,len)返回從 start 位置開始的指定長度的子字符串,第一個(gè)字符下標(biāo)為1substring-before(string1,string2)返回string1中位于第一個(gè)string2之前的部分substring-after(string1,string2)返回string1中位于第一個(gè)string2之后的部分
同樣用上面的Html文檔舉個(gè)例子
路徑表達(dá)式描述//div[position()>1]選擇第二個(gè) div 節(jié)點(diǎn)//div[last()]選擇最后一個(gè) div 節(jié)點(diǎn)contains(//h4[2],’手機(jī)’)第二個(gè) h4 標(biāo)簽是否包含手機(jī)字符串//li/text()li 節(jié)點(diǎn)中的文本內(nèi)容//div/comment()div 節(jié)點(diǎn)下的 html 注釋normalize-space(//li[@class=’blank’])li 節(jié)點(diǎn)下 class屬性為 blank 的文本去掉空格substring(//h4[1],1,2)第一個(gè) h4 節(jié)點(diǎn)的前2個(gè)字substring-before(//h4[1],’品牌商’)第一個(gè) h4 節(jié)點(diǎn)的品牌商字符串之前的字符串substring-after(//h4[1],’品牌商’)第一個(gè) h4 節(jié)點(diǎn)的品牌商字符串之后的字符串
XPath 中的謂語就是刪選表達(dá)式,相當(dāng)于 SQL 中的 Where 條件,謂語被嵌在 [ ] 中
路徑表達(dá)式描述//div[1]選擇第一個(gè) div 節(jié)點(diǎn)//div[2]/ul/li[last()]選擇第二個(gè) div 節(jié)點(diǎn)下的最后一個(gè) li 節(jié)點(diǎn)//div[2]/ul/li[position()>3]選擇第二個(gè) div 節(jié)點(diǎn)下的前兩個(gè) li 節(jié)點(diǎn)//ul[@class]選擇所有帶 class 屬性的 ul 節(jié)點(diǎn)//ul[@class=’computer’]選擇 class 屬性為 computer 的 ul 節(jié)點(diǎn)//h4[span=4]選擇 h4 節(jié)點(diǎn)下 span 值等于4的節(jié)點(diǎn)
以上內(nèi)容介紹了 XPath 的基本語法,下面將介紹 XPath 如何在 Python 中使用。
sudo pip3 install lxml==4.4.1
lxml.etree 一個(gè)強(qiáng)大的 Xml 處理模塊,etree 中的 ElementTree 類是一個(gè)主要的類,用于對(duì)XPath的解析、增加、刪除和修改節(jié)點(diǎn)。
from lxml import etree
etree.parse() 函數(shù)可以解析一個(gè)網(wǎng)頁文件還可以解析字符串, 在網(wǎng)頁中下載的數(shù)據(jù)一般都是字符串形式的,使用 parse(StringIO(str)) 將整個(gè)頁面內(nèi)容解析加載構(gòu)建一個(gè) ElementTree 對(duì)象,ElementTree 可以使用 XPath 語法精準(zhǔn)找到需要的數(shù)據(jù)。
1.加載頁面到內(nèi)存
from lxml import etree
from io import StringIO
test_html='''
<html>
<body>
<div>
<!-- 這里是注釋 -->
<h4>手機(jī)品牌商<span style="margin-left:10px">4</span></h4>
<ul>
<li>小米</li>
<li>華為</li>
<li class='blank'> OPPO </li>
<li>蘋果</li>
</ul>
</div>
<div>
<h4>電腦品牌商<span style="margin-left:10px">3</span></h4>
<ul class="ul" style="color:red">
<li>戴爾</li>
<li>機(jī)械革命</li>
<li>ThinkPad</li>
</ul>
</div>
</body>
</html>'''
html=etree.parse(StringIO(test_html))
print(html)
結(jié)果:
<lxml.etree._ElementTree object at 0x10bd6b948>
2.獲取所有 li 標(biāo)簽數(shù)據(jù)
li_list=html.xpath('//li')
print("類型:")
print(type(li_list))
print("值:")
print(li_list)
print("個(gè)數(shù):")
print(len(li_list))
for l in li_list:
print("li文本為:" + l.text)
結(jié)果:
類型:
<class 'list'>
值:
[<Element li at 0x10543c9c8>, <Element li at 0x10543ca08>, <Element li at 0x10543ca48>, <Element li at 0x10543ca88>, <Element li at 0x10543cac8>, <Element li at 0x10543cb48>, <Element li at 0x10543cb88>]
個(gè)數(shù):
7
li文本為:小米
li文本為:華為
li文本為: OPPO
li文本為:蘋果
li文本為:戴爾
li文本為:機(jī)械革命
li文本為:ThinkPad
3.獲取帶 class=’blank’ 屬性數(shù)據(jù)
blank_li_list=html.xpath('//li[@class="blank"]')
print("類型:")
print(type(blank_li_list))
print("值:")
print(blank_li_list)
print("個(gè)數(shù):")
print(len(blank_li_list))
for l in blank_li_list:
print("li文本為:" + l.text)
結(jié)果:
類型:
<class 'list'>
值:
[<Element li at 0x105253a48>]
個(gè)數(shù):
1
li文本為: OPPO
4.屬性操作
ul=html.xpath('//ul')[1]
#遍歷屬性
for name, value in ul.attrib.items():
print('{0}="{1}"'.format(name, value))
#添加新的屬性
ul.set("new_attr", "true")
# 獲取單個(gè)屬性
new_attr=ul.get('new_attr')
print(new_attr)
結(jié)果:
class="ul"
style="color:red"
true
5.獲取最后一個(gè)div標(biāo)簽數(shù)據(jù)
last_div=html.xpath('//div[last()]')
print("TAG:")
print(last_div.tag)
print("值:")
print(last_div.text)
結(jié)果
div
值:
6.添加子節(jié)點(diǎn)
child=etree.Element("child")
child.text="這里是新的子元素"
last_div.append(child)
# 在最后一個(gè) div 標(biāo)簽查找新的子元素
clild_text=last_div.find("child").text
print(clild_text)
7.刪除子元素
# 查找并設(shè)置第一個(gè)查詢到的元素
first_ul=html.find("//ul")
ul_li=first_ul.xpath("li")
for li in ul_li:
# 刪除元素
first_ul.remove(li)
ul_li=first_ul.xpath("li")
if len(ul_li)==0:
print("元素被刪除了")
8.遍歷元素后代
body=html.find("body")
for sub in body.iter():
print(sub.tag)
print(sub.text)
結(jié)果
body
div
<cyfunction Comment at 0x10c374b10>
這里是注釋
h4
手機(jī)品牌商
span
4
ul
...
慶才,Python技術(shù)控,爬蟲博文訪問量已過百萬。喜歡鉆研,熱愛生活,樂于分享。
個(gè)人博客:靜覓 | http://cuiqingcai.com/
XPath,全稱 XML Path Language,即 XML 路徑語言,它是一門在XML文檔中查找信息的語言。XPath 最初設(shè)計(jì)是用來搜尋XML文檔的,但是它同樣適用于 HTML 文檔的搜索。
所以在做爬蟲時(shí),我們完全可以使用 XPath 來做相應(yīng)的信息抽取,本節(jié)我們來介紹一下 XPath 的基本用法。
XPath 的選擇功能十分強(qiáng)大,它提供了非常簡潔明了的路徑選擇表達(dá)式,另外它還提供了超過 100 個(gè)內(nèi)建函數(shù)用于字符串、數(shù)值、時(shí)間的匹配以及節(jié)點(diǎn)、序列的處理等等,幾乎所有我們想要定位的節(jié)點(diǎn)都可以用XPath來選擇。
XPath 于 1999 年 11 月 16 日 成為 W3C 標(biāo)準(zhǔn),它被設(shè)計(jì)為供 XSLT、XPointer 以及其他 XML 解析軟件使用,更多的文檔可以訪問其官方網(wǎng)站:https://www.w3.org/TR/xpath/。
我們現(xiàn)用表格列舉一下幾個(gè)常用規(guī)則:
表達(dá)式描述
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ī)則,例如 / 代表選取直接子節(jié)點(diǎn),// 代表選擇所有子孫節(jié)點(diǎn),. 代表選取當(dāng)前節(jié)點(diǎn),.. 代表選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn),@ 則是加了屬性的限定,選取匹配屬性的特定節(jié)點(diǎn)。
例如:
//title[@lang=’eng’]
這就是一個(gè) XPath 規(guī)則,它就代表選擇所有名稱為 title,同時(shí)屬性 lang 的值為 eng 的節(jié)點(diǎn)。
在后文我們會(huì)介紹 XPath 的詳細(xì)用法,通過 Python 的 LXML 庫利用 XPath 進(jìn)行 HTML 的解析。
在使用之前我們首先要確保安裝好了 LXML 庫,如沒有安裝可以參考第一章的安裝過程。
我們現(xiàn)用一個(gè)實(shí)例來感受一下使用 XPath 來對(duì)網(wǎng)頁進(jìn)行解析的過程,代碼如下:
from lxml import etree
text='''
<div>
<ul>
<li><a >first item</a></li>
<li><a >second item</a></li>
<li><a >third item</a></li>
<li><a >fourth item</a></li>
<li><a >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 模塊可以對(duì) HTML 文本進(jìn)行自動(dòng)修正。
在這里我們調(diào)用 tostring() 方法即可輸出修正后的 HTML 代碼,但是結(jié)果是 bytes 類型,在這里我們利用 decode() 方法轉(zhuǎn)成 str 類型,結(jié)果如下:
<html><body><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>
</li></ul>
</div>
</body></html>
我們可以看到經(jīng)過處理之后 li 節(jié)點(diǎn)標(biāo)簽被補(bǔ)全,并且還自動(dòng)添加了 body、html 節(jié)點(diǎn)。
另外我們也可以直接讀取文本文件進(jìn)行解析,示例如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=etree.tostring(html)
print(result.decode('utf-8'))
其中 test.html 的內(nèi)容就是上面例子中的 HTML 代碼,內(nèi)容如下:
<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>
這次的輸出結(jié)果略有不同,多了一個(gè) DOCTYPE 的聲明,不過對(duì)解析無任何影響,結(jié)果如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><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>
</li></ul>
</div></body></html>
我們一般會(huì)用 // 開頭的 XPath 規(guī)則來選取所有符合要求的節(jié)點(diǎn),以上文的 HTML 文本為例,如果我們要選取所有節(jié)點(diǎn),可以這樣實(shí)現(xiàn):
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//*')
print(result)
運(yùn)行結(jié)果:
[<Element html at 0x10510d9c8>, <Element body at 0x10510da08>, <Element div at 0x10510da48>, <Element ul at 0x10510da88>, <Element li at 0x10510dac8>, <Element a at 0x10510db48>, <Element li at 0x10510db88>, <Element a at 0x10510dbc8>, <Element li at 0x10510dc08>, <Element a at 0x10510db08>, <Element li at 0x10510dc48>, <Element a at 0x10510dc88>, <Element li at 0x10510dcc8>, <Element a at 0x10510dd08>]
我們?cè)谶@里使用 * 代表匹配所有節(jié)點(diǎn),也就是整個(gè) HTML 文本中的所有節(jié)點(diǎn)都會(huì)被獲取,可以看到返回形式是一個(gè)列表,每個(gè)元素是 Element 類型,其后跟了節(jié)點(diǎn)的名稱,如 html、body、div、ul、li、a 等等,所有的節(jié)點(diǎn)都包含在列表中了。
當(dāng)然此處匹配也可以指定節(jié)點(diǎn)名稱,如果我們想獲取所有 li 節(jié)點(diǎn),示例如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li')
print(result)
print(result[0])
運(yùn)行結(jié)果:
[<Element li at 0x105849208>, <Element li at 0x105849248>, <Element li at 0x105849288>, <Element li at 0x1058492c8>, <Element li at 0x105849308>]
<Element li at 0x105849208>
在這里我們可以看到提取結(jié)果是一個(gè)列表形式,其每一個(gè)元素都是一個(gè) Element 對(duì)象,如果要取出其中一個(gè)對(duì)象可以直接用中括號(hào)加索引即可取出,如 [0]。
我們通過 / 或 // 即可查找元素的子節(jié)點(diǎn)或子孫節(jié)點(diǎn),加入我們現(xiàn)在想選擇 li 節(jié)點(diǎn)所有直接 a 子節(jié)點(diǎn),可以這樣來實(shí)現(xiàn):
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li/a')
print(result)
在這里我們通過追加一個(gè) /a 即選擇了所有 li 節(jié)點(diǎn)的所有直接 a 子節(jié)點(diǎn),因?yàn)?//li 是選中所有l(wèi)i節(jié)點(diǎn), /a 是選中l(wèi)i節(jié)點(diǎn)的所有直接子節(jié)點(diǎn) a,二者組合在一起即獲取了所有l(wèi)i節(jié)點(diǎn)的所有直接 a 子節(jié)點(diǎn)。
運(yùn)行結(jié)果:
[<Element a at 0x106ee8688>, <Element a at 0x106ee86c8>, <Element a at 0x106ee8708>, <Element a at 0x106ee8748>, <Element a at 0x106ee8788>]
但是此處的 / 是選取直接子節(jié)點(diǎn),如果我們要獲取所有子孫節(jié)點(diǎn)就該使用 // 了,例如我們要獲取 ul 節(jié)點(diǎn)下的所有子孫 a 節(jié)點(diǎn),可以這樣來實(shí)現(xiàn):
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//ul//a')
print(result)
運(yùn)行結(jié)果是相同的。
但是這里如果我們用 //ul/a 就無法獲取任何結(jié)果了,因?yàn)?/ 是獲取直接子節(jié)點(diǎn),而在 ul 節(jié)點(diǎn)下沒有直接的 a 子節(jié)點(diǎn),只有 li 節(jié)點(diǎn),所以無法獲取任何匹配結(jié)果,代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//ul/a')
print(result)
運(yùn)行結(jié)果:
[]
因此在這里我們要注意 / 和 // 的區(qū)別,/ 是獲取直接子節(jié)點(diǎn),// 是獲取子孫節(jié)點(diǎn)。
我們知道通過連續(xù)的 / 或 // 可以查找子節(jié)點(diǎn)或子孫節(jié)點(diǎn),那假如我們知道了子節(jié)點(diǎn)怎樣來查找父節(jié)點(diǎn)呢?在這里我們可以用 .. 來獲取父節(jié)點(diǎn)。
比如我們現(xiàn)在首先選中 href 是 link4.html 的 a 節(jié)點(diǎn),然后再獲取其父節(jié)點(diǎn),然后再獲取其 class 屬性,代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//a[@]
檢查一下結(jié)果,正是我們獲取的目標(biāo) li 節(jié)點(diǎn)的 class,獲取父節(jié)點(diǎn)成功。
同時(shí)我們也可以通過 parent:: 來獲取父節(jié)點(diǎn),代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//a[@)
print(result)
8. 屬性匹配
在選取的時(shí)候我們還可以用 @ 符號(hào)進(jìn)行屬性過濾,比如在這里如果我們要選取 class 為 item-1 的 li 節(jié)點(diǎn),可以這樣實(shí)現(xiàn):
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li[@class="item-0"]')
print(result)
在這里我們通過加入 [@class="item-0"] 就限制了節(jié)點(diǎn)的 class 屬性為 item-0,而 HTML 文本中符合條件的 li 節(jié)點(diǎn)有兩個(gè),所以返回結(jié)果應(yīng)該返回兩個(gè)匹配到的元素,結(jié)果如下:
[<Element li at 0x10a399288>, <Element li at 0x10a3992c8>]可見匹配結(jié)果結(jié)果正是兩個(gè),至于是不是那正確的兩個(gè),我們?cè)诤竺骝?yàn)證一下。
9. 文本獲取
我們用 XPath 中的 text() 方法可以獲取節(jié)點(diǎn)中的文本,我們接下來嘗試獲取一下上文 li 節(jié)點(diǎn)中的文本,代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li[@class="item-0"]/text()')
print(result)
運(yùn)行結(jié)果如下:
['\n ']很奇怪的是我們并沒有獲取到任何文本,而是只獲取到了一個(gè)換行符,這是為什么呢?因?yàn)?XPath 中 text() 前面是 /,而此 / 的含義是選取直接子節(jié)點(diǎn),而此處很明顯 li 的直接子節(jié)點(diǎn)都是 a 節(jié)點(diǎn),文本都是在 a 節(jié)點(diǎn)內(nèi)部的,所以這里匹配到的結(jié)果就是被修正的 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>
其中一個(gè)節(jié)點(diǎn)因?yàn)樽詣?dòng)修正,li 節(jié)點(diǎn)的尾標(biāo)簽添加的時(shí)候換行了,所以提取文本得到的唯一結(jié)果就是 li 節(jié)點(diǎn)的尾標(biāo)簽和 a 節(jié)點(diǎn)的尾標(biāo)簽之間的換行符。
因此,如果我們想獲取 li 節(jié)點(diǎn)內(nèi)部的文本就有兩種方式,一種是選取到 a 節(jié)點(diǎn)再獲取文本,另一種就是使用 //,我們來看下二者的區(qū)別是什么。
首先我們選取到 a 節(jié)點(diǎn)再獲取文本,代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li[@class="item-0"]/a/text()')
print(result)
運(yùn)行結(jié)果:
['first item', 'fifth item']可以看到這里返回值是兩個(gè),內(nèi)容都是屬性為 item-0 的 li 節(jié)點(diǎn)的文本,這也印證了我們上文中屬性匹配的結(jié)果是正確的。
在這里我們是逐層選取的,先選取了 li 節(jié)點(diǎn),又利用 / 選取了其直接子節(jié)點(diǎn) a,然后再選取其文本,得到的結(jié)果恰好是符合我們預(yù)期的兩個(gè)結(jié)果。
我們?cè)賮砜聪掠昧硪环N方式 // 選取的結(jié)果,代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li[@class="item-0"]//text()')
print(result)
運(yùn)行結(jié)果:
['first item', 'fifth item', '\n ']不出所料,這里返回結(jié)果是三個(gè),可想而知這里是選取所有子孫節(jié)點(diǎn)的文本,其中前兩個(gè)就是 li 的子節(jié)點(diǎn) a 節(jié)點(diǎn)內(nèi)部的文本,另外一個(gè)就是最后一個(gè) li 節(jié)點(diǎn)內(nèi)部的文本,即換行符。
所以說,如果我們要想獲取子孫節(jié)點(diǎn)內(nèi)部的所有文本,可以直接用 // 加 text() 的方式獲取,這樣可以保證獲取到最全面的文本信息,但是可能會(huì)夾雜一些換行符等特殊字符。如果我們想獲取某些特定子孫節(jié)點(diǎn)下的所有文本,可以先選取到特定的子孫節(jié)點(diǎn),然后再調(diào)用 text() 方法獲取其內(nèi)部文本,這樣可以保證獲取的結(jié)果是整潔的。
10. 屬性獲取
我們知道了用 text() 可以獲取節(jié)點(diǎn)內(nèi)部文本,那么節(jié)點(diǎn)屬性該怎樣獲取呢?其實(shí)還是用 @ 符號(hào)就可以,例如我們想獲取所有 li 節(jié)點(diǎn)下所有 a 節(jié)點(diǎn)的 href 屬性,代碼如下:
from lxml import etree
html=etree.parse('./test.html', etree.HTMLParser())
result=html.xpath('//li/a/@href')
print(result)
在這里我們通過 @href 即可獲取節(jié)點(diǎn)的 href 屬性,注意此處和屬性匹配的方法不同,屬性匹配是中括號(hào)加屬性名和值來限定某個(gè)屬性,如 [@],而此處的 @href 指的是獲取節(jié)點(diǎn)的某個(gè)屬性,二者需要做好區(qū)分。
運(yùn)行結(jié)果:
['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']可以看到我們成功獲取了所有 li 節(jié)點(diǎn)下的 a 節(jié)點(diǎn)的 href 屬性,以列表形式返回。
11. 屬性多值匹配
有時(shí)候某些節(jié)點(diǎn)的某個(gè)屬性可能有多個(gè)值,例如下面例子:
from lxml import etree
text='''
<li class="li li-first"><a >first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[@class="li"]/a/text()')
print(result)
在這里 HTML 文本中的 li 節(jié)點(diǎn)的 class 屬性有兩個(gè)值 li 和 li-first,但是此時(shí)如果我們還想用之前的屬性匹配獲取就無法匹配了,代碼運(yùn)行結(jié)果:
[]這時(shí)如果屬性有多個(gè)值就需要用 contains() 函數(shù)了,代碼可以改寫如下:
from lxml import etree
text='''
<li class="li li-first"><a >first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class, "li")]/a/text()')
print(result)
這樣我們通過 contains() 方法,第一個(gè)參數(shù)傳入屬性名稱,第二個(gè)參數(shù)傳入屬性值,這樣只要此屬性包含所傳入的屬性值就可以完成匹配了。
運(yùn)行結(jié)果:
['first item']此種選擇方式在某個(gè)節(jié)點(diǎn)的某個(gè)屬性有多個(gè)值的時(shí)候經(jīng)常會(huì)用到,如某個(gè)節(jié)點(diǎn)的 class 屬性通常有多個(gè)。
12. 多屬性匹配
另外我們可能還遇到一種情況,我們可能需要根據(jù)多個(gè)屬性才能確定一個(gè)節(jié)點(diǎn),這是就需要同時(shí)匹配多個(gè)屬性才可以,那么這里可以使用運(yùn)算符 and 來連接,示例如下:
from lxml import etree
text='''
<li class="li li-first" name="item"><a >first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result)
在這里 HTML 文本的 li 節(jié)點(diǎn)又增加了一個(gè)屬性 name,這時(shí)候我們需要同時(shí)根據(jù) class 和 name 屬性來選擇,就可以 and 運(yùn)算符連接兩個(gè)條件,兩個(gè)條件都被中括號(hào)包圍,運(yùn)行結(jié)果如下:
['first item']這里的 and 其實(shí)是 XPath 中的運(yùn)算符,另外還有很多運(yùn)算符,如 or、mod 等等,在此總結(jié)如下:
運(yùn)算符描述實(shí)例返回值
or或price=9.80 or price=9.70如果 price 是 9.80,則返回 true。如果 price 是 9.50,則返回 false。
and與price>9.00 and price<9.90如果 price 是 9.80,則返回 true。如果 price 是 8.50,則返回 false。
mod計(jì)算除法的余數(shù)5 mod 21
\計(jì)算兩個(gè)節(jié)點(diǎn)集//book \//cd返回所有擁有 book 和 cd 元素的節(jié)點(diǎn)集
+加法6 + 410
-減法6 - 42
*乘法6 * 424
div除法8 div 42
=等于price=9.80如果 price 是 9.80,則返回 true。如果 price 是 9.90,則返回 false。
!=不等于price!=9.80如果 price 是 9.90,則返回 true。如果 price 是 9.80,則返回 false。
<小于price<9.80如果 price 是 9.00,則返回 true。如果 price 是 9.90,則返回 false。
<=小于或等于price<=9.80如果 price 是 9.00,則返回 true。如果 price 是 9.90,則返回 false。
>大于price>9.80如果 price 是 9.90,則返回 true。如果 price 是 9.80,則返回 false。
>=大于或等于price>=9.80如果 price 是 9.90,則返回 true。如果 price 是 9.70,則返回 false。
此表參考來源:http://www.w3school.com.cn/xpath/xpath_operators.asp。
13. 按序選擇
有時(shí)候我們?cè)谶x擇的時(shí)候可能某些屬性同時(shí)匹配了多個(gè)節(jié)點(diǎn),但是我們只想要其中的某個(gè)節(jié)點(diǎn),如第二個(gè)節(jié)點(diǎn),或者最后一個(gè)節(jié)點(diǎn),這時(shí)該怎么辦呢?
這時(shí)可以利用中括號(hào)傳入索引的方法獲取特定次序的節(jié)點(diǎn),示例如下:
from lxml import etree
text='''
<div>
<ul>
<li><a >first item</a></li>
<li><a >second item</a></li>
<li><a >third item</a></li>
<li><a >fourth item</a></li>
<li><a >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)
第一次選擇我們選取了第一個(gè) li 節(jié)點(diǎn),中括號(hào)中傳入數(shù)字1即可,注意這里和代碼中不同,序號(hào)是以 1 開頭的,不是 0 開頭的。
第二次選擇我們選取了最后一個(gè) li 節(jié)點(diǎn),中括號(hào)中傳入 last() 即可,返回的便是最后一個(gè) li 節(jié)點(diǎn)。
第三次選擇我們選取了位置小于 3 的 li 節(jié)點(diǎn),也就是位置序號(hào)為 1 和 2 的節(jié)點(diǎn),得到的結(jié)果就是前 2 個(gè) li 節(jié)點(diǎn)。
第四次選擇我們選取了倒數(shù)第三個(gè) li 節(jié)點(diǎn),中括號(hào)中傳入 last()-2即可,因?yàn)?last() 是最后一個(gè),所以 last()-2 就是倒數(shù)第三個(gè)。
運(yùn)行結(jié)果如下:
['first item']
['fifth item']
['first item', 'second item']
['third item']
在這里我們使用了 last()、position() 等函數(shù),XPath 中提供了 100 多個(gè)函數(shù),包括存取、數(shù)值、字符串、邏輯、節(jié)點(diǎn)、序列等處理功能,具體所有的函數(shù)作用可以參考:http://www.w3school.com.cn/xpath/xpath_functions.asp。
14. 節(jié)點(diǎn)軸選擇
XPath 提供了很多節(jié)點(diǎn)軸選擇方法,英文叫做 XPath Axes,包括獲取子元素、兄弟元素、父元素、祖先元素等等,在一定情況下使用它可以方便地完成節(jié)點(diǎn)的選擇,我們用一個(gè)實(shí)例來感受一下:
from lxml import etree
text='''
<div>
<ul>
<li><a ><span>first item</span></a></li>
<li><a >second item</a></li>
<li><a >third item</a></li>
<li><a >fourth item</a></li>
<li><a >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[@)
print(result)
運(yùn)行結(jié)果:
[<Element html at 0x107941808>, <Element body at 0x1079418c8>, <Element div at 0x107941908>, <Element ul at 0x107941948>]
[<Element div at 0x107941908>]
['item-0']
[<Element a at 0x1079418c8>]
[<Element span at 0x107941948>]
[<Element a at 0x1079418c8>]
[<Element li at 0x107941948>, <Element li at 0x107941988>, <Element li at 0x1079419c8>, <Element li at 0x107941a08>]
第一次選擇我們調(diào)用了 ancestor 軸,可以獲取所有祖先節(jié)點(diǎn),其后需要跟兩個(gè)冒號(hào),然后是節(jié)點(diǎn)的選擇器,這里我們直接使用了 *,表示匹配所有節(jié)點(diǎn),因此返回結(jié)果是第一個(gè) li 節(jié)點(diǎn)的所有祖先節(jié)點(diǎn),包括 html,body,div,ul。
第二次選擇我們又加了限定條件,這次在冒號(hào)后面加了 div,這樣得到的結(jié)果就只有 div 這個(gè)祖先節(jié)點(diǎn)了。
第三次選擇我們調(diào)用了 attribute 軸,可以獲取所有屬性值,其后跟的選擇器還是 *,這代表獲取節(jié)點(diǎn)的所有屬性,返回值就是 li 節(jié)點(diǎn)的所有屬性值。
第四次選擇我們調(diào)用了 child 軸,可以獲取所有直接子節(jié)點(diǎn),在這里我們又加了限定條件選取 href 屬性為 link1.html 的 a 節(jié)點(diǎn)。
第五次選擇我們調(diào)用了 descendant 軸,可以獲取所有子孫節(jié)點(diǎn),這里我們又加了限定條件獲取 span 節(jié)點(diǎn),所以返回的就是只包含 span 節(jié)點(diǎn)而沒有 a 節(jié)點(diǎn)。
第六次選擇我們調(diào)用了 following 軸,可以獲取當(dāng)前節(jié)點(diǎn)之后的所有節(jié)點(diǎn),這里我們雖然使用的是 * 匹配,但又加了索引選擇,所以只獲取了第二個(gè)后續(xù)節(jié)點(diǎn)。
第七次選擇我們調(diào)用了 following-sibling 軸,可以獲取當(dāng)前節(jié)點(diǎn)之后的所有同級(jí)節(jié)點(diǎn),這里我們使用的是 * 匹配,所以獲取了所有后續(xù)同級(jí)節(jié)點(diǎn)。
以上是XPath軸的簡單用法,更多的軸的使用可以參考:http://www.w3school.com.cn/xpath/xpath_axes.asp。
End.
運(yùn)行人員:中國統(tǒng)計(jì)網(wǎng)小編(微信號(hào):itongjilove)
微博ID:中國統(tǒng)計(jì)網(wǎng)
中國統(tǒng)計(jì)網(wǎng),是國內(nèi)最早的大數(shù)據(jù)學(xué)習(xí)網(wǎng)站,公眾號(hào):中國統(tǒng)計(jì)網(wǎng)
http://www.itongji.cn
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。