Python3 爬蟲學(xué)習(xí)(五) - XPath 語法和 lxml 模塊

什么是 XPath

XPath(XML Path Language) 是一門在 XML 和 HTML 文檔中查找信息的語言,可用來在 XML 和 HTML 文檔中對元素和屬性進(jìn)行遍歷。

XPath 開發(fā)工具

1.Chrome 插件 XPath Helper
2.Firefox 插件 XPath Checker

XPath 語法

  • 選取節(jié)點

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

表達(dá)式 描述 示例 結(jié)果
nodename 選取此節(jié)點的所有子節(jié)點 bookstore 選取 bookstore 下所有的子節(jié)點
/ 如果是在最前面,代表從根節(jié)點選取。否則選擇某節(jié)點下的某個節(jié)點 /bookstore 選取根元素下所有的 bookstore 節(jié)點
// 從全局節(jié)點中選擇節(jié)點,隨便在哪個位置 //book 從全局節(jié)點中找到所有的 book 節(jié)點
@ 選取某個節(jié)點的屬性 //book[@price] 選擇所有 book 節(jié)點的 price 屬性
  • 謂詞
路徑表達(dá)式 描述
/bookstore/book[1] 選取 bookstore 下的第一個子元素
/bookstore/book[last()] 選取 bookstore 下的最后一個 book 元素
bookstore/book[position()<3] 選取 bookstore 下前面兩個子元素
//book[@price] 選取擁有 price 屬性的 book 元素
//book[@price=10] 選取所有屬性 price 等于 10 的 book 元素
//book/a/text() 選取所有 book 標(biāo)簽下的 a 標(biāo)簽的文本
  • 通配符

* 星號表示通配符

通配符 描述 示例 結(jié)果
* 匹配任意節(jié)點 /bookstore/* 選取 bookstore 下的所有子元素
@* 匹配節(jié)點中的任何屬性 //book[@*] 選取所有帶有屬性的 book 元素
  • 選取多個路徑

通過在路徑表達(dá)式中使用 "|" 運算符,可以選取若干個路徑。
示例如下:

//bookstore/book* | //book/title
# 選取所有 book 元素以及 book 元素下所有的 title 元素

  • 運算符
運算符 描述 實例 返回值
| 計算兩個節(jié)點集 //book | //cd 返回所有擁有 book 和 cd 元素的節(jié)點集
+ 加法 6 + 4 10
- 減法 6 - 4 2
* 乘法 6 * 4 24
div 除法 8 div 4 2
= 等于 price=9.80 如果 price 是 9.80,則返回 true,否則返回 false
!= 不等于 price!=9.80 如果 price 不是 9.80,則返回 true,否則返回 false
< 小于 price<9.80 如果 price 小于 9.80,則返回 true,否則返回 false
<= 小于等于 price<=9.80 ...
> 大于 price>9.80 ...
>= 大于等于 price>=9.80 ...
or price=9.80 or price=9.70 ...
and price>9.00 and price<9.90 ...
mod 計算除法的余數(shù) 5 mod 2 1
  • contains

有時候某個屬性包含多個值,就可以使用 contains 函數(shù),示例代碼如下:

//div[contains(@class, 'job_detail')

lxml 庫

lxml 是一個 HTML/XML 的解析庫,主要功能是如何解析和提取 HTML/XML 數(shù)據(jù)。

lxml 和 正則是一樣,也是用 C 語言實現(xiàn)的,是一款高性能的 Python HTML/XML 解析器,可以利用之前學(xué)習(xí)的 XPath 語法,來快速定位特定元素以及節(jié)點信息。

lxml python 官方文檔:http://lxml.de/index.html

可通過 pip 安裝:pip install lxml

  • 基本使用

我們可以利用他來解析 HTML 代碼,且在解析 HTML 代碼的時候,如果 HTML 代碼不規(guī)范,他會自動進(jìn)行補全。示例代碼如下:

from lxml.html import etree

htmlText = '''
<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(htmlText)

# 按字符串序列化 HTML 文檔
result = etree.tostring(html, encoding='utf-8', pretty_print=True).decode('utf-8')

print(result)
  • 在文件中讀取 html 代碼

除了直接使用字符串進(jìn)行解析,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">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.parse() 方法來讀取讀取文件,如下:

from lxml.html import etree

html = etree.parse('files/hello.html')
result = etree.tostring(html, encoding='utf-8', pretty_print=True).decode('utf-8')
print(result)

另外,需要注意的是,使用 etree.parse() 方法解析 html 內(nèi)容時,有時候會報 lxml.etree.XMLSyntaxError 的錯,這是因為 etree.parse() 默認(rèn)使用的是 XML 的解析器,所以當(dāng) html 內(nèi)容不規(guī)范,比如出現(xiàn)某個標(biāo)簽缺少閉合標(biāo)簽時,就會報這個錯誤。這時,可使用 etree.HTMLParser() 創(chuàng)建一個 HTML 的解析器,然后作為 etree.parse() 方法的參數(shù)即可,如下:

htmlParser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('files/hello.html', parser=htmlParser)
result = etree.tostring(html, encoding='utf-8', pretty_print=True).decode('utf-8')
print(result)
  • 在 lxml 中使用 XPath 語法

(1) 使用 xpath 語法,應(yīng)該使用 Element.xpath 語法,來執(zhí)行 xpath 的選擇
(2) xpath 函數(shù)返回來的永遠(yuǎn)是一個列表

from lxml.html import etree

htmlParser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('files/hello.html', parser=htmlParser)
# htmlText = etree.tostring(html, encoding='utf-8', pretty_print=True).decode('utf-8')
# print(htmlText)

lis = html.xpath('//li')
for li in lis:
    print(etree.tostring(li, encoding='utf-8', pretty_print=True).decode('utf-8'), end='')

aList = html.xpath('//a/@href')
for a in aList:
    print(a)

print('-----------------------')

lis = html.xpath('//li')
for li in lis:
    # . 號表示在當(dāng)前的 li 元素下去匹配
    href = li.xpath('.//a/@href')[0]   #獲取 a 標(biāo)簽的 href 屬性
    txt = li.xpath('.//a/text()')[0]   #獲取 a 標(biāo)簽的文本
    print(href, txt)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容