Python爬蟲(十二)_XPath與lxml類庫
有同學說,我正則用的不好,處理HTML文件很累,有沒有其他的方法?
有!那就是XPath,我們可以用先將HTML文件轉換成XML文件,然後用XPath查詢HTML節點或元素。
什麼是XML
- XML指可擴充套件標記語言(Extensible Markup Language)
- XML是一種標記語言,很類似HTML
- XML的設計宗旨是傳輸資料,而非顯示資料。
- XML的標籤需要我們自行定義。
- XML被設計為具有自我描述性。
- XML是W3C的推薦標準。
W3School官方文件:http://www.w3school.com.cn/xml/index.asp
XML和HTML的區別
資料格式 | 描述 | 設計目標 |
---|---|---|
XML | Extensible Markup Language (可擴充套件標記語言) | 被設計為傳輸和儲存資料,其焦點是資料的內容。 |
HTML | HyperText Markup Language(超文字標記語言) | 顯示資料以及如何更好顯示資料。 |
HTML DOM | Document Object Model for HTML (文件物件模型) | 通過 HTML DOM,可以訪問所有的 HTML 元素,連同它們所包含的文字和屬性。可以對其中的內容進行修改和刪除,同時也可以建立新的元素。 |
XML文件例項
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book category="cooking"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="web"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <price>49.99</price> </book> <book category="web" cover="paperback"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>
HTML DOM模型示例
HTML DOM定義了訪問和操作HTML文件的標準方法,以樹結構方式表達了HTML文件。
XML的節點關係
1.父(Parent)
每個元素以及屬性都有一個父。
下面是一個簡單的XML例子中,book元素時title、author、year以及price
<?xml version="1.0" encoding="utf-8"?> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book>
2.子(Children)
元素節點可能有零個、一個或多個子。
在下面的例子中,title、author、year以及price元素都是book元素的子:
<?xml version="1.0" encoding="utf-8"?> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book>
3.同胞(Sibling)
擁有相同的父的節點
在下面的例子中,title、author、year以及price元素都是同胞:
<?xml version="1.0" encoding="utf-8"?> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book>
4.先輩(Ancestor)
某節點的父、父的父,等等。
在下面的例子中,title元素的先輩是book元素和bookstore元素:
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> </bookstore>
5.後代
某個節點的子,子的子,等等。
在下面的例子中,bookstore的後代是book、title、author、year以及price元素:
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> </bookstore>
什麼是XPath?
XPath(XML Path Language)是一門在XML文件中查詢資訊的語言,可用來在XML中對元素和屬性進行遍歷。
W3School官方文件:http://www.w3school.com.cn/xpath/index.asp
XPath 開發工具
- 開源的XPath表示式編輯工具:XML Quire(XML格式檔案可用)
- Chrome外掛Xpath Helper
- Firefox外掛Xpath Checker
選取節點
XPath使用路徑表示式來選取XML文件中的節點或者節點集。這些路徑表示式和我們常規的電腦檔案系統中看到的表示式非常相似。
下面列出了最常用的路徑表示式:
表示式 | 描述 |
---|---|
nodename | 選取此節點的所有子節點 |
/ | 從根節點選取 |
// | 從匹配選擇的當前節點選擇文件中的節點,而不考慮它們的位置。 |
. | 選取當前節點。 |
.. | 選取當前節點的父節點 |
@ | 選取屬性 |
在下面的表格中,我們已列出了一些路徑表示式以及表示式的結果:
路徑表示式 | 描述 |
---|---|
bookstore | 選取bookstore元素的所有子節點。 |
/bookstore | 選取根元素 bookstore。註釋:假如路徑起始於正斜槓( / ),則此路徑始終代表到某元素的絕對路徑! |
bookstore/book | 選取屬於bookstore的子元素的所有book元素 |
//book | 選取所有book子元素,而不管它們在文件中的位置 |
bookstore//book | 選擇屬於bookstore元素的後代的所有bok元素,而不管它們位於bookstore之下的什麼位置 |
//@lang | 選取名為lang的所有屬性。 |
謂語(Predicates)
謂語用來查詢某個特定的節點或者包含某個特定的值的節點,被嵌在方括號中。
在下面的表格中,我們列出了帶有謂語的一些路徑表示式,以及表示式的結果:
路徑表示式 | 結果 |
---|---|
/bookstore/book[1] | 選取屬於bookstore子元素的第一個book元素。 |
/bookstore/book[last()] | 選取資料bookstore子元素的最後一個book元素 |
/bookstore/book[last()-1] | 選取屬於bookstore元素的倒數第二個book元素 |
/bookstore/book[position()<3] | 選取最前面的兩個屬於bookstore元素的子元素book元素 |
//title[@lang] | 選取所有擁有名為lang的屬性的title元素 |
//title[@lang="eng"] | 選取所有title元素,且這些元素擁有值為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元素。
萬用字元 | 描述 |
---|---|
* | 匹配任何元素節點 |
@* | 匹配任何屬性節點 |
node() | 匹配任何型別的節點 |
在下面的表格中,我們列出了一些路徑表示式,以及這些表示式的結果:
路徑表示式 | 結果 |
---|---|
/bookstore/* | 選取bookstore元素的所有子元素 |
//* | 選取文件中的所有元素 |
title[@*] | 選取所有帶屬性的title元素 |
選取若干路徑
通過在路徑表示式中使用"|"運算子,您可以選取若干個路勁。
例項
在下面的表格中,我們列出了一些路徑表示式,以及這些表示式的結果:
路徑表示式 | 結果 |
---|---|
'//book/title | //book/price' | 選取book元素的所有title和price元素。 |
//title | //price | 選取文件中的所有title和price元素 |
/bookstore/book/title | //price | 選取屬於bookstore元素的book元素的title元素,以及文件中的所有price元素 |
XPath的運算子
以上就是XPath的語法內容,在運用到Python抓取時要先轉換為xml.
lxml庫
lxml是一個HTML/XML的解析器,主要的功能是如何提取和解析HTML/XML資料。
lxml和正則一樣,也是用C實現,是一款高效能的Python HTML/XML解析器,我們可以利用之前學習的XPath語法,來快速的定位特定元素以及節點資訊。
lxml python官方文件:http://lxml.de/index.html
需要安裝C語言庫,可使用pip安裝:pip install lxml(或通過wheel方式安裝)
初步使用
我們利用它來解析HTML程式碼,簡單例項:
#-*- coding:utf-8 -*-
#lxml_test.py
#使用lxml的etree庫
from lxml import etree text = ''' <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> ''' #利用etree.HTML,將字串解析為HTML文件 html = etree.HTML(text) #按字串序列化為HTML文件 result = etree.tostring(html) print(result)
輸出結果:
<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>
lxml可以自動修正html程式碼,例子裡不僅補全裡li標籤,還添加了body/html標籤
檔案讀取:
除了直接讀取字串,lxml還支援從檔案裡讀取內容。我們新建一個hello.html文件:
<!--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>
再利用etree.parse()方法來讀取檔案。
#lxml_parse.py
from lxml import etree
#讀取外部檔案hello.html
html = etree.parse('./hello.html') result = etree.tostring(html, pretty_print=True) print(result)
輸出結果與之前相同:
<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>
XPath例項測試
1.獲取所有的<li>
標籤
#xpath_li.py
from lxml import etree
html = etree.parse('hello.html')
print type(html) #顯示etree.parse()返回型別 result = html.xpath('//li') print result #列印<li>標籤的的元素集合 print len(result) print type(result) print type(result[0])
輸出結果:
<type 'lxml.etree._ElementTree'>
[<Element li at 0x1014e0e18>, <Element li at 0x1014e0ef0>, <Element li at 0x1014e0f38>, <Element li at 0x1014e0f80>, <Element li at 0x1014e0fc8>] 5 <type 'list'> <type 'lxml.etree._Element'>
2.繼續獲取<li>
標籤的所有class
屬性
#xpath_li.py
from lxml import etree
html = etree.parse('htllo.html')
result = html.xpath('//li/@class') print result
執行結果:
['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
3.繼續獲取<li>
標籤下href
為link1.html
的<a>
標籤
#xpath_li.py
from lxml import etree
html = etree.parse('hello.html')
result = html.xpath('//li/a[@href="link1.html"]') print result
執行結果:
[<Element a at 0x10ffaae18>]
4.獲取<li>
標籤下的所有<span>
標籤
#xpath_li.py
from lxml import etree
html = etree.parse('hello.html')
#result = html.xpath('//li/span') #注意這麼寫是不對的 #因為/是用來獲取子元素的,而<span>不是<li>的子元素,所以,要用雙斜槓 result = html.xpath('//li//span') print result
執行結果:
[<Element span at 0x10d698e18>]
5.獲取<li>
標籤下的<a>
標籤裡的所有class
from lxml import etree
html = etree.parse('hello.html')
result = html.xpath('//li/a//@class')
print result
執行結果
['blod']
6.獲取最後一個<li>
的<a>
的href
#xpath_li.py
from lxml import etree
html = etree.parse('hello.html')
result = html.xpath('//li[last()]/a/@href') #謂語[last()]可以找到最後一個元素 print result
執行結果
['link5.html']
7.獲取倒數第二個元素的內容
#xpath_li.py
from lxml import etree
html = etree.parse('hello.html')
result = html.xpath('//li[last()-1]/a') #text方法可以獲取元素內容 print(result[0].text)
執行結果
fourth item
8.獲取class
值為bold
的標籤名
#xpath_li.py
from lxml import etree
html = etree.parse('hello.html')
result = html.xpath('//*[@class="bold"]') #tag方法可以獲取標籤名 print result[0].tag
執行結果
span
有同學說,我正則用的不好,處理HTML文件很累,有沒有其他的方法?
有!那就是XPath,我們可以用先將HTML文件轉換成XML文件,然後用XPath查詢HTML節點或元素。
什麼是XML
- XML指可擴充套件標記語言(Extensible Markup Language)
- XML是一種標記語言,很類似HTML
- XML的設計宗旨是傳輸資料,而非顯示資料。
- XML的標籤需要我們自行定義。
- XML被設計為具有自我描述性。
- XML是W3C的推薦標準。
W3School官方文件:http://www.w3school.com.cn/xml/index.asp
XML和HTML的區別
資料格式 | 描述 | 設計目標 |
---|---|---|
XML | Extensible Markup Language (可擴充套件標記語言) | 被設計為傳輸和儲存資料,其焦點是資料的內容。 |
HTML | HyperText Markup Language(超文字標記語言) | 顯示資料以及如何更好顯示資料。 |
HTML DOM | Document Object Model for HTML (文件物件模型) | 通過 HTML DOM,可以訪問所有的 HTML 元素,連同它們所包含的文字和屬性。可以對其中的內容進行修改和刪除,同時也可以建立新的元素。 |
XML文件例項
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book category="cooking"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="web"> <title lang="en">XQuery Kick Start</title> <author>James McGovern</author> <author>Per Bothner</author> <author>Kurt Cagle</author> <author>James Linn</author> <author>Vaidyanathan Nagarajan</author> <year>2003</year> <price>49.99</price> </book> <book category="web" cover="paperback"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore>
HTML DOM模型示例
HTML DOM定義了訪問和操作HTML文件的標準方法,以樹結構方式表達了HTML文件。
XML的節點關係
1.父(Parent)
每個元素以及屬性都有一個父。
下面是一個簡單的XML例子中,book元素時title、author、year以及price
<?xml version="1.0" encoding="utf-8"?> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book>
2.子(Children)
元素節點可能有零個、一個或多個子。
在下面的例子中,title、author、year以及price元素都是book元素的子:
<?xml version="1.0" encoding="utf-8"?> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book>
3.同胞(Sibling)
擁有相同的父的節點
在下面的例子中,title、author、year以及price元素都是同胞:
<?xml version="1.0" encoding="utf-8"?> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book>
4.先輩(Ancestor)
某節點的父、父的父,等等。
在下面的例子中,title元素的先輩是book元素和bookstore元素:
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> </bookstore>
5.後代
某個節點的子,子的子,等等。
在下面的例子中,bookstore的後代是book、title、author、year以及price元素:
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book> <title>Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> </bookstore>
什麼是XPath?
XPath(XML Path Language)是一門在XML文件中查詢資訊的語言,可用來在XML中對元素和屬性進行遍歷。
W3School官方文件:http://www.w3school.com.cn/xpath/index.asp
XPath 開發工具
- 開源的XPath表示式編輯工具:XML Quire(XML格式檔案可用)
- Chrome外掛Xpath Helper
- Firefox外掛Xpath Checker
選取節點
XPath使用路徑表示式來選取XML文件中的節點或者節點集。這些路徑表示式和我們常規的電腦檔案系統中看到的表示式非常相似。
下面列出了最常用的路徑表示式:
表示式 | 描述 |
---|---|
nodename | 選取此節點的所有子節點 |
/ | 從根節點選取 |
// | 從匹配選擇的當前節點選擇文件中的節點,而不考慮它們的位置。 |
. | 選取當前節點。 |
.. | 選取當前節點的父節點 |
@ | 選取屬性 |
在下面的表格中,我們已列出了一些路徑表示式以及表示式的結果:
路徑表示式 | 描述 |
---|---|
bookstore | 選取bookstore元素的所有子節點。 |
/bookstore | 選取根元素 bookstore。註釋:假如路徑起始於正斜槓( / ),則此路徑始終代表到某元素的絕對路徑! |
bookstore/book | 選取屬於bookstore的子元素的所有book元素 |
//book | 選取所有book子元素,而不管它們在文件中的位置 |
bookstore//book | 選擇屬於bookstore元素的後代的所有bok元素,而不管它們位於bookstore之下的什麼位置 |
//@lang | 選取名為lang的所有屬性。 |
謂語(Predicates)
謂語用來查詢某個特定的節點或者包含某個特定的值的節點,被嵌在方括號中。
在下面的表格中,我們列出了帶有謂語的一些路徑表示式,以及表示式的結果:
路徑表示式 | 結果 |
---|---|
/bookstore/book[1] | 選取屬於bookstore子元素的第一個book元素。 |
/bookstore/book[last()] | 選取資料bookstore子元素的最後一個book元素 |
/bookstore/book[last()-1] | 選取屬於bookstore元素的倒數第二個book元素 |
/bookstore/book[position()<3] | 選取最前面的兩個屬於bookstore元素的子元素book元素 |
//title[@lang] | 選取所有擁有名為lang的屬性的title元素 |
//title[@lang="eng"] | 選取所有title元素,且這些元素擁有值為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元素。
萬用字元 | 描述 |
---|---|
* | 匹配任何元素節點 |
@* | 匹配任何屬性節點 |
node() | 匹配任何型別的節點 |
在下面的表格中,我們列出了一些路徑表示式,以及這些表示式的結果:
路徑表示式 | 結果 |
---|---|
/bookstore/* | 選取bookstore元素的所有子元素 |
//* | 選取文件中的所有元素 |
title[@*] | 選取所有帶屬性的title元素 |
選取若干路徑
通過在路徑表示式中使用"|"運算子,您可以選取若干個路勁。
例項
在下面的表格中,我們列出了一些路徑表示式,以及這些表示式的結果:
路徑表示式 | 結果 |
---|---|
'//book/title | //book/price' | 選取book元素的所有title和price元素。 |
//title | //price | 選取文件中的所有title和price元素 |
/bookstore/book/title | //price | 選取屬於bookstore元素的book元素的title元素,以及文件中的所有price元素 |
XPath的運算子
以上就是XPath的語法內容,在運用到Python抓取時要先轉換為xml.
lxml庫
lxml是一個HTML/XML的解析器,主要的功能是如何提取和解析HTML/XML資料。
lxml和正則一樣,也是用C實現,是一款高效能的Python HTML/XML解析器,我們可以利用之前學習的XPath語法,來快速的定位特定元素以及節點資訊。
lxml python官方文件:http://lxml.de/index.html
需要安裝C語言庫,可使用pip安裝:pip install lxml(或通過wheel方式安裝)
初步使用
我們利用它來解析HTML程式碼,簡單例項:
#-*- coding:utf-8 -*-
#lxml_test.py
#使用lxml的etree庫
from lxml import etree text = ''' <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> ''' #利用etree.HTML,將字串解析為HTML文件 html = etree.HTML(text) #按字串序列化為HTML文件 result = etree.tostring(html) print(result)
輸出結果:
<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>
lxml可以自動修正html程式碼,例子裡不僅補全裡li標籤,還添加了body/html標籤
檔案讀取:
除了直接讀取字串,lxml還支援從檔案裡讀取內容。我們新建一個hello.html文件:
<!--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>