人生苦短,我用 Pythonhtml
前文傳送門:python
小白學 Python 爬蟲(2):前置準備(一)基本類庫的安裝github
小白學 Python 爬蟲(3):前置準備(二)Linux基礎入門ajax
小白學 Python 爬蟲(4):前置準備(三)Docker基礎入門數據庫
小白學 Python 爬蟲(5):前置準備(四)數據庫基礎框架
小白學 Python 爬蟲(6):前置準備(五)爬蟲框架的安裝ide
小白學 Python 爬蟲(10):Session 和 Cookies
小白學 Python 爬蟲(11):urllib 基礎使用(一)
小白學 Python 爬蟲(12):urllib 基礎使用(二)
小白學 Python 爬蟲(13):urllib 基礎使用(三)
小白學 Python 爬蟲(14):urllib 基礎使用(四)
小白學 Python 爬蟲(15):urllib 基礎使用(五)
小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖
小白學 Python 爬蟲(17):Requests 基礎使用
小白學 Python 爬蟲(18):Requests 進階操做
文接上篇,咱們接着聊,上篇咱們介紹了 Xpath 一些經常使用的匹配方式, DOM 節點咱們能夠匹配出來了,這並非咱們的最終目的,咱們是要從這些節點中取出來咱們想要的數據。本篇咱們接着介紹如何使用 Xpath 獲取數據。
咱們先嚐試下獲取第一篇文章的題目,獲取節點中的文本咱們可使用 text()
來進行獲取,如圖:
代碼以下:
from lxml import etree
import requests
response = requests.get('https://www.geekdigging.com/')
html_str = response.content.decode('UTF-8')
html = etree.HTML(html_str)
result_1 = html.xpath('/html/body/section/div/div/main/article[1]/div[2]/div/h3/a/text()')
print(result_1)複製代碼
結果以下:
['小白學 Python 爬蟲(18):Requests 進階操做']複製代碼
哇,上面示例裏面的表達式好長啊,這個怎麼寫出來的,怎麼寫的稍後再說,先介紹一下這個表達式的意思,仔細看一下,這個表達式實際上是從整個 HTML 源代碼的最外層的 標籤寫起,一層一層的定位到了咱們所須要的節點,而後再使用
text()
方法獲取了其中的文本內容。
關於這個表達式怎麼來的,確定不是小編寫的,這麼寫講實話是有點傻,徹底不必從整個文檔的最外層開始寫。
其實這個是 Chrome 幫咱們生成的,具體操做可見下圖:
這時 Chrome 會自動幫咱們把這個節點的表達式 copy 到當前的剪切板上,只須要咱們在程序裏 ctrl + v
一下。
有些狀況下,咱們可能不止須要節點中的文本數據,可能還會須要節點中的屬性數據,好比上面的示例,咱們除了想知道文章標題,其實還想知道文章的跳轉路徑:
result_2 = html.xpath('/html/body/section/div/div/main/article[1]/div[2]/div/h3/a/@href')
print(result_2)複製代碼
結果以下:
['/2019/12/11/1468953802/']複製代碼
這裏須要注意的是,此處和屬性匹配的方法不一樣,屬性匹配是中括號加屬性名和值來限定某個屬性,如 [@class="container"]
,而此處的 @href
指的是獲取節點的某個屬性,兩者須要作好區分。
某些時候吧,某些節點的某個屬性可能有多個值,這個多見於 class
屬性,因爲某些編碼習慣以及某些其餘緣由,這個屬性常常性會出現多個值,這時若是隻使用其中的一個值的話,就沒法匹配了。
若是這麼寫的話:
result_3 = html.xpath('//div[@class="post-head"]')
print(result_3)複製代碼
結果以下:
[]複製代碼
能夠看到,這裏沒有匹配到任何節點,這時,咱們可使用一個函數:contains()
,上面的示例能夠改爲這樣:
result_3 = html.xpath('//div[contains(@class, "post-head")]')
print(result_3)複製代碼
這樣經過 contains()
方法,第一個參數傳入屬性名稱,第二個參數傳入屬性值,只要此屬性包含所傳入的屬性值,就能夠進行匹配了。
除了上面的一個屬性有多個值的狀況,還常常會出現須要使用多個屬性才能肯定一個惟一的節點。
這時,咱們可使用運算符來進行處理。
仍是這個示例,咱們獲取
這個節點,若是隻是使用 class 屬性來進行獲取,會得到不少個節點:
result_4 = html.xpath('//img[@class="img-ajax"]')
print(result_4)複製代碼
結果以下:
[<Element img at 0x1984505a788>, <Element img at 0x1984505a7c8>, <Element img at 0x1984505a808>, <Element img at 0x1984505a848>, <Element img at 0x1984505a888>, <Element img at 0x1984505a908>, <Element img at 0x1984505a948>, <Element img at 0x1984505a988>, <Element img at 0x1984505a9c8>, <Element img at 0x1984505a8c8>, <Element img at 0x1984505aa08>, <Element img at 0x1984505aa48>]複製代碼
若是咱們加上 alt 屬性一塊兒進行匹配的話,就能夠得到惟一的節點:
result_4 = html.xpath('//img[@class="img-ajax" and @alt="小白學 Python 爬蟲(18):Requests 進階操做"]')
print(result_4)複製代碼
結果以下:
[<Element img at 0x299905e6a48>]複製代碼
Xpath 支持不少的運算符,詳細見下表(來源:https://www.w3school.com.cn/xpath/xpath_operators.asp)
有些時候,咱們匹配出來不少的節點,可是咱們只想獲取其中的某一個節點,好比第一個或者最後一個,這時可使用中括號傳入索引的方法獲取特定次序的節點。
咱們仍是文章的題目爲例,咱們先獲取全部的文章題目,再進行選擇,示例代碼以下:
result_5 = html.xpath('//article/div/div/h3[@class="post-title"]/a/text()')
print(result_5)
result_6 = html.xpath('//article[1]/div/div/h3[@class="post-title"]/a/text()')
print(result_6)
result_7 = html.xpath('//article[last()]/div/div/h3[@class="post-title"]/a/text()')
print(result_7)
result_8 = html.xpath('//article[position() < 5]/div/div/h3[@class="post-title"]/a/text()')
print(result_8)複製代碼
結果以下:
['小白學 Python 爬蟲(18):Requests 進階操做', '小白學 Python 爬蟲(17):Requests 基礎使用', '小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖', '如何用 Python 寫一個簡易的抽獎程序', '小白學 Python 爬蟲(15):urllib 基礎使用(五)', '咱們真的在被 APP 「竊聽」 麼?', '小白學 Python 爬蟲(14):urllib 基礎使用(四)', '小白學 Python 爬蟲(13):urllib 基礎使用(三)', '小白學 Python 爬蟲(12):urllib 基礎使用(二)', '小白學 Python 爬蟲(11):urllib 基礎使用(一)', '老司機大型車禍現場', '小白學 Python 爬蟲(10):Session 和 Cookies']
['小白學 Python 爬蟲(18):Requests 進階操做']
['小白學 Python 爬蟲(10):Session 和 Cookies']
['小白學 Python 爬蟲(18):Requests 進階操做', '小白學 Python 爬蟲(17):Requests 基礎使用', '小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖', '如何用 Python 寫一個簡易的抽獎程序']複製代碼
第一次,咱們選取了當前頁面全部的文章的題目。
第二次,咱們選擇了當前頁面第一篇文章的題目,這裏注意下,中括號中傳入數字1便可,這裏的開始是以 1 爲第一個的,不是程序中的 0 爲第一個。
第三次,咱們使用 last()
函數,獲取了最後一篇文章的題目。
第四次,咱們選擇了位置小於 5 的文章題目。
軸可定義相對於當前節點的節點集。
軸名稱 |
結果 |
---|---|
ancestor |
選取當前節點的全部先輩(父、祖父等)。 |
ancestor-or-self |
選取當前節點的全部先輩(父、祖父等)以及當前節點自己。 |
attribute |
選取當前節點的全部屬性。 |
child |
選取當前節點的全部子元素。 |
descendant |
選取當前節點的全部後代元素(子、孫等)。 |
descendant-or-self | 選取當前節點的全部後代元素(子、孫等)以及當前節點自己。 |
following |
選取文檔中當前節點的結束標籤以後的全部節點。 |
namespace |
選取當前節點的全部命名空間節點。 |
parent |
選取當前節點的父節點。 |
preceding |
選取文檔中當前節點的開始標籤以前的全部節點。 |
preceding-sibling |
選取當前節點以前的全部同級節點。 |
self |
選取當前節點。 |
咱們以 ancestor
軸來作示例:
# 節點軸示例
# 獲取全部祖先節點
result_9 = html.xpath('//article/ancestor::*')
print(result_9)
# 獲取祖先節點 main 節點
result_10 = html.xpath('//article/ancestor::main')
print(result_10)複製代碼
結果以下:
[<Element html at 0x2a266171208>, <Element body at 0x2a266171248>, <Element section at 0x2a266171288>, <Element div at 0x2a2661712c8>, <Element div at 0x2a266171308>, <Element main at 0x2a266171388>]
[<Element main at 0x2a266171388>]複製代碼
關於節點軸就先介紹到這裏,更多的軸的用法能夠參考:https://www.w3school.com.cn/xpath/xpath_axes.asp 。
本系列的全部代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便你們取用。