什么是 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)