更新時間:2021-06-21 來源:黑馬程序員 瀏覽量:
lxml是使用Python語言編寫的庫,主要用于解析和提取HTML或者XML格式的數(shù)據(jù),它不僅功能非常豐富,而且便于使用,可以利用XPath語法快速地定位特定的元素或節(jié)點。
lxml庫中大部分功能都位于lxml.etree模塊中,導(dǎo)入lxml.etree模塊的常見方式如下:
from lxml import etree
lxml庫的一些相關(guān)類如下:
(1) Element類:可以理解為XML的節(jié)點。
(2) ElementTree類:可以理解為一個完整的XML文檔樹。
(3) ElementPath類:可以理解為XPath,用于搜索和定位節(jié)點。
1.Element 類簡介
Element類是XML處理的核心類,可以直觀地理解為XML的節(jié)點,大部分XML節(jié)點的處理都是圍繞著Element類進(jìn)行的。要想創(chuàng)建一個節(jié)點對象,則可以通過構(gòu)造函數(shù)直接創(chuàng)建。例如:
root=etree.Element('root')
上述示例中,參數(shù)root表示節(jié)點的名稱。 關(guān)于Element類的相關(guān)操作,主要可分為三部分,分別是節(jié)點操作、節(jié)點屬性的操作、節(jié)點內(nèi)文本的操作,下面進(jìn)行逐一介紹。 (1)節(jié)點操作:若要獲取節(jié)點的名稱,可以通過tag屬性獲取。例如:
print(root.tag) # 輸出結(jié)果如下 root
(2)節(jié)點屬性的操作:在創(chuàng)建節(jié)點的同時,可以為節(jié)點增加屬性。節(jié)點中的屬性是以key-value的形式進(jìn)行存儲的,類似于字典的存儲方式。通過構(gòu)造方法創(chuàng)建節(jié)點時,可以在該方法中以參數(shù)的形式設(shè)置屬性,其中參數(shù)的名稱表示屬性的名稱,參數(shù)的值表示為屬性的值。創(chuàng)建屬性的示例如下:
# 創(chuàng)建root節(jié)點,并為其添加屬性 root=etree.Element('root', interesting='totally') print(etree.tostring(root)) # 輸出結(jié)果如下 b'<root interesting=" totally" />'
此外,可以通過set()方法給已有的節(jié)點添加屬性。在調(diào)用該方法時可以傳入兩個參數(shù),其中第一個參數(shù)表示屬性的名稱,第二個參數(shù)表示屬性的值。例如:
# 再次給root節(jié)點添加age屬性 root.set('age', '30') print(etree.tostring(root)) # 輸出結(jié)果如下 b'<root interesting="totally"age="30"/>'
在上述兩個示例中,都用到了tostring()函數(shù),該函數(shù)可以將元素序列化為XML樹的編碼字符串表示形式。
(3)節(jié)點內(nèi)文本的操作:一般情況下,可以通過text、tail屬性或者xpath()方法來訪問文本內(nèi)容。通過text屬性訪問節(jié)點的示例如下:
root=etree.Element('root') # 創(chuàng)建root節(jié)點 root.text='Hello, World!' # 給root節(jié)點添加文本 print(root.text) print(etree.tostring(root)) # 輸出結(jié)果如下 Hello, world! b'<root>Hello, World!</root>'
2.從字符串或文件中解析XML
為了能夠?qū)ML文件解析為樹結(jié)構(gòu),etree模塊中提供了如下3個函數(shù): (1 ) fromstring()函數(shù):從字符串中解析XML文檔或片段,返回根節(jié)點(或解析器目標(biāo)返回的結(jié)果)。 (2) XML()函數(shù):從字符串常量中解析XML文檔或片段,返回根節(jié)點(或解析器目標(biāo)返回的結(jié)果)。 (3) HTML()函數(shù):從字符串常量中解析HTML文檔或片段,返回根節(jié)點(或解析器目標(biāo)返回的結(jié)果)。 其中,XML()函數(shù)的行為類似于fromstring0函數(shù),通常用于將XML字面量直接寫入到源代碼中;HTML()函數(shù)可以自動補(bǔ)全缺少的<html>和<body>標(biāo)簽。以上3個函數(shù)的示例如下:
xml_data='<root>data</root>' # fromstring()方法 root_one=etree.fromstring(xml_data) print(root_one.tag) print(etree.tostring(root_one)) # XML方法,與fromstring方法基本一樣 root_two=etree.XML(xml_data) print(root_two.tag) print(etree.tostring(root_two)) # HTML()方法,如果沒有<html>和<body>標(biāo)簽,會自動補(bǔ)上 root_three=etree.HTML(xml_data) print(root_three.tag) print(etree.tostring(root_three)) 程序運行結(jié)果為: root b'<root>data</root>' root b'<root>data</root>' html b'<html><body><root>data</root></body></html>'
除了上述3個函數(shù)之外,還可以調(diào)用parse()函數(shù)從XML文件中直接解析。在調(diào)用函數(shù)時,如果沒有提供解析器,則使用默認(rèn)的解析器,函數(shù)會返回一個ElemenfTree 類的對象。例如:
html=etree.parse('./hello.html') result=etree.tostring(html, pretty_print=True)
ElementPath類簡介
ElementTree類中附帶了一個類似于XPath路徑語言的ElementPath類。在ElementTree類或Elements類的API文檔中,提供了3個常用的方法,可以滿足大部分搜索和查詢需求,并且這3個方法的參數(shù)都是XPath語句。具體如下: (1) find()方法:返回匹配到的第一 個子元素。 (2) findall()方法:以列表的形式返回所有匹配的子元素。 (3) iterfind()方法:返回一個所有匹配元素的迭代器。 從文檔樹的根節(jié)點開始,搜索符合要求的節(jié)點。例如:
# 從字符串中解析XML,返回根節(jié)點 root=etree.XML("<root><a x='123'>aText<b/><c/><b/></a></root>") # 從根節(jié)點查找,返回匹配到的節(jié)點名稱 print(root.find("a").tag) # 從根節(jié)點開始查找,返回匹配到的第一個節(jié)點的名稱 print(root.findall(".//a[@x]")[0].tag)
程序運行結(jié)果為:
a A
還可以調(diào)用xpath()方法,使用元素作為上下文節(jié)點來評估XPath表達(dá)式。
lxml庫的基本使用
這里使用一個HTML示例文件作為素材來介紹lxml庫的基本應(yīng)用。該文件名為hello.html,內(nèi)容如下:
<!-- hello.html --> <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"><span class="bold">third item</span></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>
按下來,基于上述HTML文檔,使用lxml庫中的路徑表達(dá)式技巧,通過調(diào)用xpath()方法匹配選取的節(jié)點,具體如下:
獲取任意位置的li節(jié)點 可以直接使用“//”從任意位置選取節(jié)點li,路徑表達(dá)式如下:
//li
通過lxml.etree模塊的xpath()方法,將hello.html文件中與該路徑表達(dá)式匹配到的列表返回,并打印輸出。具體代碼如下:
from lxml import etree html=etree.parse('hello.html') # 查找所有的li節(jié)點 result=html.xpath('//li') # 打印<li>標(biāo)簽的元素集合 print(result) # 打印<li>標(biāo)簽的個數(shù) print(len(result)) # 打印返回結(jié)果的類型 print(type(result)) # 打印第一個元素的類型 print(type(result[0]))
程序運行結(jié)果為:
[<Element li at 0x2cc9a48>, <Element li at 0x2cc99c8>, <Element li at 0x2cc9a88>, <Element li at 0x2cc9ac8>, <Element li at 0x2cc9b08>] 5 <class 'list'> <class 'lxml.etree._Element'>
繼續(xù)獲取<li>標(biāo)簽的class屬性
在上個表達(dá)式的末尾,使用“/”向下選取節(jié)點,并使用@選取class屬性節(jié)點,表達(dá)式如下:
//1i/@class
獲取<li>標(biāo)簽的class屬性的示例代碼如下:
from lxml import etree html=etree.parse('hello.html') # 查找位于li標(biāo)簽的class屬性 result=html.xpath('//li/@class') print(result)
程序運行結(jié)果為:
['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
獲取倒數(shù)第二個元素的內(nèi)容
從任意位置開始選取倒數(shù)第二個<li>標(biāo)簽,再向下選取標(biāo)簽<a>。如果要獲取該標(biāo)簽中的 文本,可以使用如下表達(dá)式:
//li[last()-1]/a
或者
//li[last()-1]/a]/text()
不同的是,第個表達(dá)式需要訪問text屬性,才能拿到標(biāo)簽的文本,而第二個表達(dá)式可直 接獲取文本。使用第一 個路徑表達(dá)式的示例如下:
from lxml import etree html=etree.parse('hello.html') # 獲取倒數(shù)第二個元素的內(nèi)容 result=html.xpath('//li[last()-1]/a') print(result[0].text)
程序運行結(jié)果:
fourth item