lxml是python的一個(gè)解析庫(kù)族展,支持HTML和XML的解析审葬,支持XPath解析方式深滚,而且解析效率非常高
XPath,全稱XML Path Language涣觉,即XML路徑語(yǔ)言痴荐,它是一門在XML文檔中查找信息的語(yǔ)言,它最初是用來(lái)搜尋XML文檔的官册,但是它同樣適用于HTML文檔的搜索
XPath的選擇功能十分強(qiáng)大生兆,它提供了非常簡(jiǎn)明的路徑選擇表達(dá)式,另外膝宁,它還提供了超過(guò)100個(gè)內(nèi)建函數(shù)鸦难,用于字符串、數(shù)值员淫、時(shí)間的匹配以及節(jié)點(diǎn)合蔽、序列的處理等,幾乎所有我們想要定位的節(jié)點(diǎn)介返,都可以用XPath來(lái)選擇
XPath的常用規(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) |
@ | 選取屬性 |
* | 通配符圣蝎,選擇所有元素節(jié)點(diǎn)與元素名 |
@* | 選取所有屬性 |
[@attrib] | 選取具有給定屬性的所有元素 |
[@attrib='value'] | 選取給定屬性具有給定值的所有元素 |
[tag] | 選取所有具有指定元素的直接子節(jié)點(diǎn) |
[tag='text'] | 選取所有具有指定元素并且文本內(nèi)容是text節(jié)點(diǎn) |
構(gòu)建etree實(shí)例
首先需要引入etree
from lxml import etree
etree.HTML()
解析字符串格式的HTML文檔對(duì)象刃宵,將傳進(jìn)去的字符串轉(zhuǎn)變成_Element對(duì)象。
-- text:HTML文檔的字符串格式parse()
讀取HTML文件進(jìn)行解析徘公,將其轉(zhuǎn)變成_Element對(duì)象牲证。
-- source:文件路徑
-- parser:該方法默認(rèn)使用的是“XML”解析器,所以如果碰到不規(guī)范的html文件時(shí)就會(huì)解析錯(cuò)誤步淹,需要將此參數(shù)設(shè)置為etree.HTMLParser()etree.tostring()
將_Element對(duì)象轉(zhuǎn)換成字符串从隆。
注意:
- etree.tostring()方法返回的是bytes類型诚撵,需要調(diào)用decode方法將其改變編碼類型。
- 解析html代碼時(shí)键闺,會(huì)自動(dòng)修正寿烟,添加缺少的標(biāo)簽。
XPath語(yǔ)法實(shí)例
- 選中所有節(jié)點(diǎn)
# 選中所有的節(jié)點(diǎn)
html = etree.parse("./test.html", etree.HTMLParser())
results = html.xpath("http://*")
print(results)
# 選中所有的li節(jié)點(diǎn)
results = html.xpath("http://li")
print(results)
print(results[0])
- 選中子節(jié)點(diǎn)
# 選中直接子節(jié)點(diǎn)
html = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("http://li/a")
print(result)
# 選取所有子孫節(jié)點(diǎn)
result = html.xpath("http://ul//a")
print(result)
- 選取父親節(jié)點(diǎn)
html = etree.parse("./test.html",etree.HTMLParser())
# 選中屬性href='link4.html'的a標(biāo)簽的父親
result = html.xpath("http://a[@href='link4.html']/..")
print(result)
# 選中屬性href='link4.html'的a標(biāo)簽的父親的class屬性
result = html.xpath("http://a[@href='link4.html']/../@class")
print(result)
# 使用parent:: 選中父親
result = html.xpath("http://a[@href='link4.html']/parent::*/@class")
print(result)
- 按屬性選取節(jié)點(diǎn)
html = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("http://li[@class='item-0']")
print(result)
- 獲取節(jié)點(diǎn)文本內(nèi)容
需要調(diào)用text()函數(shù)
html = etree.parse("./test.html", etree.HTMLParser())
print(etree.tostring(html).decode("utf-8"))
# 使用/僅獲取自身的文本內(nèi)容
result = html.xpath("http://li[@class='item-0']/text()")
print(result) # 輸出:['\r\n\t']
# 使用//獲取自己以及子孫的文本內(nèi)容
result = html.xpath("http://li[@class='item-0']//text()")
print(result) # 輸出:['first item', 'fifth item', '\r\n\t']
- 獲取節(jié)點(diǎn)屬性的值
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("http://li/a/@href")
print(result)
- 多值屬性匹配
需要使用contains()函數(shù)
text = '''
<li class="li li-first"><a href="link1.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath("http://li[@class='li']/a/text()")
print(result) # 輸出 []
result = html.xpath("http://li[contains(@class,'li')]/a/text()")
print(result) # 輸出:['first item']
- 多屬性匹配
text = '''
<li class="li li-first" name="item"><a href="link1.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath("http://li[contains(@class,'li') and @name='item']/a/text()")
print(result)
and 是xpath中的運(yùn)算符辛燥。常見(jiàn)的運(yùn)算符如下:
運(yùn)算符 | 描述 | 實(shí)例 |
---|---|---|
or | 或 | age=19 or age=20 |
and | 與 | age >19 and age <21 |
mod | 取余數(shù) | 5 mod 2 |
計(jì)算兩個(gè)節(jié)點(diǎn)集 | //book | //cd :返回所有擁有book和cd元素的節(jié)點(diǎn)集 | |
+ | 加法 | 6 + 4 |
- | 減法 | 6 - 4 |
* | 乘法 | 6 * 3 |
div | 除法 | 6 div 3 |
= | 等于 | age=19 |
!= | 不等于 | age !=19 |
< | 小于 | age <19 |
<= | 小于或等于 | age <= 19 |
> | 大于 | age >19 |
>= | 大于或等于 | age >= 19 |
- 按順序選取節(jié)點(diǎn)
html = etree.parse("./test.html",etree.HTMLParser())
# 選取第一個(gè)節(jié)點(diǎn)
result = html.xpath("http://li[1]/a/text()")
print(result)
# 選取最后一個(gè)節(jié)點(diǎn)
result = html.xpath("http://li[last()]/a/text()")
print(result)
# 選取前兩個(gè)節(jié)點(diǎn)
result = html.xpath('//li[position() < 3]/a/text()')
print(result)
# 選取倒數(shù)第三個(gè)節(jié)點(diǎn)
result = html.xpath("http://li[last()-2]/a/text()")
print(result)
- 按節(jié)點(diǎn)軸選取元素
text = '''
<div>
<ul>
<li class="item-0" name="first-li"><a href="link1.html"><span>first item</span></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("http://li[1]/ancestor::*")
print(result)
# 選中祖先中的div
result = html.xpath("http://li[1]/ancestor::div")
print(result)
# 獲取所有的屬性值
result = html.xpath("http://li[1]/attribute::*")
print(result)
# 找到直接子節(jié)點(diǎn)中滿足條件的元素
result = html.xpath("http://li[1]/child::a[@href='link1.html']")
print(result)
# 找到所有的后代元素
result = html.xpath("http://li[1]/descendant::*")
print(result)
# 找到后代元素中的span
result = html.xpath("http://li[1]/descendant::span")
print(result)
# 獲取該節(jié)點(diǎn)后面的兄弟節(jié)點(diǎn)以及這些兄弟節(jié)點(diǎn)的子孫節(jié)點(diǎn)
result = html.xpath("http://li[1]/following::*")
print(result)
# 獲取該節(jié)點(diǎn)后面的兄弟節(jié)點(diǎn)以及這些兄弟節(jié)點(diǎn)的子孫節(jié)點(diǎn)中的第一個(gè)節(jié)點(diǎn)
result = html.xpath("http://li[1]/following::*[1]")
print(result)
# 獲取該節(jié)點(diǎn)后面的所有兄弟節(jié)點(diǎn)
result = html.xpath("http://li[1]/following-sibling::*")
print(result)