Python爬蟲(十二)_XPath與lxml類庫

Python學習指南

有同學說,我正則用的不好茉稠,處理HTML文檔很累描馅,有沒有其他的方法?
有而线!那就是XPath,我們可以用先將HTML文檔轉(zhuǎn)換成XML文檔铭污,然后用XPath查找HTML節(jié)點或元素。

什么是XML

  • XML指可擴展標記語言(Extensible Markup Language)
  • XML是一種標記語言膀篮,很類似HTML
  • XML的設(shè)計宗旨是傳輸數(shù)據(jù)嘹狞,而非顯示數(shù)據(jù)。
  • XML的標簽需要我們自行定義誓竿。
  • XML被設(shè)計為具有自我描述性磅网。
  • XML是W3C的推薦標準。

W3School官方文檔:http://www.w3school.com.cn/xml/index.asp

XML和HTML的區(qū)別

數(shù)據(jù)格式 描述 設(shè)計目標
XML Extensible Markup Language (可擴展標記語言) 被設(shè)計為傳輸和存儲數(shù)據(jù)烤黍,其焦點是數(shù)據(jù)的內(nèi)容知市。
HTML HyperText Markup Language(超文本標記語言) 顯示數(shù)據(jù)以及如何更好顯示數(shù)據(jù)傻盟。
HTML DOM Document Object Model for HTML (文檔對象模型) 通過 HTML DOM,可以訪問所有的 HTML 元素嫂丙,連同它們所包含的文本和屬性娘赴。可以對其中的內(nèi)容進行修改和刪除跟啤,同時也可以創(chuàng)建新的元素诽表。

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文檔的標準方法,以樹結(jié)構(gòu)方式表達了HTML文檔隅肥。

HTML DOM

XML的節(jié)點關(guān)系

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)
元素節(jié)點可能有零個、一個或多個子秃症。
在下面的例子中候址,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)
擁有相同的父的節(jié)點
在下面的例子中岗仑,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)
某節(jié)點的父荠雕、父的父,等等驶赏。
在下面的例子中炸卑,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.后代
某個節(jié)點的子,子的子母市,等等矾兜。
在下面的例子中,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 開發(fā)工具

  1. 開源的XPath表達式編輯工具:XML Quire(XML格式文件可用)
  2. Chrome插件Xpath Helper
  3. Firefox插件Xpath Checker

選取節(jié)點

XPath使用路徑表達式來選取XML文檔中的節(jié)點或者節(jié)點集。這些路徑表達式和我們常規(guī)的電腦文件系統(tǒng)中看到的表達式非常相似篙挽。
下面列出了最常用的路徑表達式:

表達式 描述
nodename 選取此節(jié)點的所有子節(jié)點
/ 從根節(jié)點選取
// 從匹配選擇的當前節(jié)點選擇文檔中的節(jié)點荆萤,而不考慮它們的位置。
. 選取當前節(jié)點。
.. 選取當前節(jié)點的父節(jié)點
@ 選取屬性

在下面的表格中链韭,我們已列出了一些路徑表達式以及表達式的結(jié)果:

路徑表達式 描述
bookstore 選取bookstore元素的所有子節(jié)點偏竟。
/bookstore 選取根元素 bookstore。注釋:假如路徑起始于正斜杠( / )敞峭,則此路徑始終代表到某元素的絕對路徑踊谋!
bookstore/book 選取屬于bookstore的子元素的所有book元素
//book 選取所有book子元素,而不管它們在文檔中的位置
bookstore//book 選擇屬于bookstore元素的后代的所有bok元素旋讹,而不管它們位于bookstore之下的什么位置
//@lang 選取名為lang的所有屬性殖蚕。

謂語(Predicates)

謂語用來查找某個特定的節(jié)點或者包含某個特定的值的節(jié)點,被嵌在方括號中沉迹。
在下面的表格中睦疫,我們列出了帶有謂語的一些路徑表達式,以及表達式的結(jié)果:

路徑表達式 結(jié)果
/bookstore/book[1] 選取屬于bookstore子元素的第一個book元素鞭呕。
/bookstore/book[last()] 選取數(shù)據(jù)bookstore子元素的最后一個book元素
/bookstore/book[last()-1] 選取屬于bookstore元素的倒數(shù)第二個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

選取未知節(jié)點

XPath通配符可用來選取未知的XML元素缨伊。

通配符 描述
* 匹配任何元素節(jié)點
@* 匹配任何屬性節(jié)點
node() 匹配任何類型的節(jié)點

在下面的表格中,我們列出了一些路徑表達式进宝,以及這些表達式的結(jié)果:

路徑表達式 結(jié)果
/bookstore/* 選取bookstore元素的所有子元素
//* 選取文檔中的所有元素
title[@*] 選取所有帶屬性的title元素

選取若干路徑

通過在路徑表達式中使用"|"運算符,您可以選取若干個路勁枷恕。
實例
在下面的表格中党晋,我們列出了一些路徑表達式,以及這些表達式的結(jié)果:

路徑表達式 結(jié)果
'//book/title | //book/price' 選取book元素的所有title和price元素徐块。
//title &#124 //price 選取文檔中的所有title和price元素
/bookstore/book/title | //price 選取屬于bookstore元素的book元素的title元素未玻,以及文檔中的所有price元素

XPath的運算符

xpath運算符

以上就是XPath的語法內(nèi)容,在運用到Python抓取時要先轉(zhuǎn)換為xml.

lxml庫

lxml是一個HTML/XML的解析器胡控,主要的功能是如何提取和解析HTML/XML數(shù)據(jù)扳剿。
lxml和正則一樣,也是用C實現(xiàn)昼激,是一款高性能的Python HTML/XML解析器庇绽,我們可以利用之前學習的XPath語法,來快速的定位特定元素以及節(jié)點信息橙困。
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)

輸出結(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>

lxml可以自動修正html代碼辟狈,例子里不僅補全里li標簽,還添加了body/html標簽

文件讀取:

除了直接讀取字符串哼转,lxml還支持從文件里讀取內(nèi)容明未。我們新建一個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)

輸出結(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>

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])

輸出結(jié)果:

<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.繼續(xù)獲取<li>標簽的所有class屬性

#xpath_li.py
from lxml import etree

html = etree.parse('htllo.html')
result = html.xpath('//li/@class')

print result

運行結(jié)果:

['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']

3.繼續(xù)獲取<li>標簽下hreflink1.html<a>標簽

#xpath_li.py
from lxml import etree

html = etree.parse('hello.html')
result = html.xpath('//li/a[@href="link1.html"]')

print result

運行結(jié)果:

[<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

運行結(jié)果:

[<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

運行結(jié)果

['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

運行結(jié)果

['link5.html']

7.獲取倒數(shù)第二個元素的內(nèi)容

#xpath_li.py
from lxml import etree

html = etree.parse('hello.html')

result = html.xpath('//li[last()-1]/a')

#text方法可以獲取元素內(nèi)容
print(result[0].text)

運行結(jié)果

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

運行結(jié)果

span
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末庶溶,一起剝皮案震驚了整個濱河市煮纵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偏螺,老刑警劉巖行疏,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異套像,居然都是意外死亡酿联,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門夺巩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贞让,“玉大人,你說我怎么就攤上這事柳譬≡牛” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵美澳,是天一觀的道長销部。 經(jīng)常有香客問我,道長制跟,這世上最難降的妖魔是什么舅桩? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮雨膨,結(jié)果婚禮上擂涛,老公的妹妹穿的比我還像新娘。我一直安慰自己聊记,他們只是感情好撒妈,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著甥雕,像睡著了一般踩身。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上社露,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天挟阻,我揣著相機與錄音,去河邊找鬼。 笑死附鸽,一個胖子當著我的面吹牛脱拼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坷备,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼熄浓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了省撑?” 一聲冷哼從身側(cè)響起赌蔑,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竟秫,沒想到半個月后娃惯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡肥败,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年趾浅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馒稍。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡皿哨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纽谒,到底是詐尸還是另有隱情证膨,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布鼓黔,位于F島的核電站椎例,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏请祖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一脖祈、第九天 我趴在偏房一處隱蔽的房頂上張望肆捕。 院中可真熱鬧,春花似錦盖高、人聲如沸慎陵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽席纽。三九已至,卻和暖如春撞蚕,著一層夾襖步出監(jiān)牢的瞬間润梯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纺铭,地道東北人寇钉。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像舶赔,于是被迫代替她去往敵國和親扫倡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容