iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 7
0

昨天有提到,Beautiful Soup 也可以用 lxml 來作為剖析器,但在某些特殊情況還是得回頭以 lxml 來使用 XPath 定位資料。

安裝 lxml 的方式可以參考昨天的文章,今天也沿用昨天的 HTML 原始內容。

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
</body></html>
"""

XPath 常用語法

選擇節點(selecting nodes)

語法 說明
node-name 選擇名稱等於 node-name 的節點
/ 選擇直屬於當前節點的所有節點(子節點)
// 選擇當前節點下所有節點(子孫節點)
. 選擇當前節點
.. 選擇上一層節點(父節點)
@ 選擇屬性

以我們使用的 HTML 原始內容來說:

查詢路徑 結果
/html 取得 html 標籤(以 / 開頭代表從根節點開始找)
/html/body/a 取得 body 下所有 a 標籤(無結果,因為 ap 底下)
//a 取得所有 a 標籤
/html/body//a 取得 body 下所有 a 標籤
//a/@href 取得所有 a 標籤的 href 屬性

用 lxml 的 etree.HTML() 方法載入 HTML 原始資料後,可以用 .xpath() 方法來執行 XPath 查詢:

from lxml import etree

# 載入 HTML 原始資料
html = etree.HTML(html_doc)

print(html.xpath('/html'))
print(html.xpath('/html/body/a'))
print(html.xpath('//a'))
print(html.xpath('/html/body//a'))
print(html.xpath('//a/@href'))

https://ithelp.ithome.com.tw/upload/images/20190923/201078751i1oXIIeRF.png

判斷式(predicates)

[] 包起來,用來對查詢加上一些額外的限制

判斷式 結果
/html/body//a[1] 取得 body 下第一個 a 標籤
/html/body//a[last() - 1] 取得 body 下最後一個 a 標籤
/html/body//a[position() < 3] 取得 body 下前兩個 a 標籤
//p[@class] 取得有定義 class 屬性的 p 標籤
//p[@class='title'] 取得 class 屬性值為 title 的 p 標籤
print(html.xpath('/html/body//a[1]'))
print(html.xpath('/html/body//a[last() - 1]'))
print(html.xpath('/html/body//a[position() < 3]'))
print(html.xpath('//p[@class]'))
print(html.xpath('//p[@class="title"]'))

https://ithelp.ithome.com.tw/upload/images/20190923/2010787536RokXDiIU.png

選取任意節點

XPath 也支援萬用字元(wildcards)來選取任意節點

萬用字元 說明
* 任意標籤
@* 任意屬性

以我們使用的 HTML 原始內容來說:

查詢路徑 結果
/html/body/* 取得 body 標籤的全部子節點
/html/body//* 取得 body 下全部標籤
//p[@*] 取得至少有定義一個屬性的 p 標籤
print(html.xpath('/html/body/*'))
print(html.xpath('/html/body//*'))
print(html.xpath('//p[@*]'))

https://ithelp.ithome.com.tw/upload/images/20190923/20107875vIIf0bPo1Q.png

一次選取多個路徑

如果想要一次查詢多組路徑,可以用 | 來達成。

通常在所需資料分散多處,但不想查詢多次時會用到。(因為分次查詢會打亂資料順序)

查詢路徑 結果
//p | //a 一次取得全部 p 標籤和 a 標籤
print(html.xpath('//p | //a'))

https://ithelp.ithome.com.tw/upload/images/20190923/20107875hPjvJRwNdw.png


用 Python 來剖析原始資料的方式就介紹到這邊!明天再了解怎麼在網路上取得原始資料後,後天就可以開始蒐集資料囉!

參考資料


上一篇
【Day 5】剖析網頁原始內容 (1/2) - HTML
下一篇
【Day 7】請求和回應
系列文
爬蟲在手、資料我有 - 30 天 Scrapy 爬蟲實戰33

尚未有邦友留言

立即登入留言