人生苦短,我用 Python
前文傳送門:
小白學 Python 爬蟲(2):前置准備(一)基本類庫的安裝
小白學 Python 爬蟲(3):前置准備(二)Linux基礎入門
小白學 Python 爬蟲(4):前置准備(三)Docker基礎入門
小白學 Python 爬蟲(6):前置准備(五)爬蟲框架的安裝
小白學 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 進階操作
小白學 Python 爬蟲(21):解析庫 Beautiful Soup(上)
小白學 Python 爬蟲(22):解析庫 Beautiful Soup(下)
小白學 Python 爬蟲(23):解析庫 pyquery 入門
小白學 Python 爬蟲(26):為啥買不起上海二手房你都買不起
小白學 Python 爬蟲(27):自動化測試框架 Selenium 從入門到放棄(上)
小白學 Python 爬蟲(28):自動化測試框架 Selenium 從入門到放棄(下)
小白學 Python 爬蟲(29):Selenium 獲取某大型電商網站商品信息
小白學 Python 爬蟲(31):自己構建一個簡單的代理池
小白學 Python 爬蟲(32):異步請求庫 AIOHTTP 基礎入門
小白學 Python 爬蟲(33):爬蟲框架 Scrapy 入門基礎(一)
小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)
引言
我們之前有介紹過通過 pyquery 、 Beautiful Soup 、 lxml 來提取網頁數據。
但是在 Scrapy 中,同樣也提供了自己獨有的數據提取方式,即 Selector(選擇器)。Selector 是基於 lxml 來構建的,支持 XPath 選擇器、CSS 選擇器以及正則表達式,功能全面,解析速度和准確度非常高。
獨立使用
Scrapy Selectors 是 Parsel 庫的包裝。包裝的目的是提供與 Scrapy Response 對象的更好的集成。
Parsel 是一個獨立的 Web 抓取庫,無需 Scrapy 即可使用。它在后台使用 lxml 庫,並在 lxml API 之上實現了一個簡單的 API 。這意味着 Scrapy 選擇器的速度和解析精度與 lxml 非常相似。
我們可以寫一個簡單的示例代碼來測試一下 Selectors 的單獨使用。
from scrapy import Selector
body = '<html><head><title>Hello Python</title></head></html>'
selector = Selector(text=body)
title = selector.xpath('//title/text()').extract_first()
print(title)
執行結果如下:
Hello Python
這個簡單的示例我們並沒有在 Scrapy 框架中執行,而是把 Scrapy 中的 Selector 單獨拿出來使用了。
Selector 的使用同其他解析庫類似,如果方便的話,我們也可以在其他項目中直接使用 Selector 來提取數據。
Scrapy Shell
由於 Selector 主要是與 Scrapy 結合使用,如 Scrapy 的回調函數中的參數 response 直接調用 xpath() 或者 css() 方法來提取數據,所以在這里我們借助 Scrapy shell 來模擬 Scrapy 請求的過程,來講解相關的提取方法。
這里我們借助官方文檔的示例進行演示。
https://docs.scrapy.org/en/latest/_static/selectors-sample1.html
為了完整起見,以下是其完整的HTML代碼:
<html>
<head>
<base href='http://example.com/' />
<title>Example website</title>
</head>
<body>
<div id='images'>
<a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
<a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
<a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
<a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
<a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
</div>
</body>
</html>
首先,讓我們開啟 Scrapy shell,在命令行輸入如下命令:
scrapy shell https://docs.scrapy.org/en/latest/_static/selectors-sample1.html
這時,我們進入了 Scrapy Shell 模式,其實就是 Scrapy 發起了一次請求,然后把一些可操作的變量傳遞給我們:
Xpath 選擇器
目前我們在 Scrapy shell 之中,這里我們主要操作的對象是 response 。
response 有一個屬性是 selector ,我們可以通過調用 response.selector.xpath 對數據進行獲取,同時, Scrapy 為我們提供了兩個更加簡潔的方法, response.xpath() 和 response.css() ,這兩個方法完全等同於 response.selector.xpath() 和 response.selector.css() 。
出於寫法上的簡便考慮,小編后續的代碼將全部使用 response.xpath() 和 response.css() 。
首先,我們簡單的獲取一下 a 標簽:
>>> result = response.xpath('//a')
>>> result
[<Selector xpath='//a' data='<a href="image1.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image2.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image3.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image4.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image5.html">Name: My image ...'>]
>>> type(result)
<class 'scrapy.selector.unified.SelectorList'>
這里我們獲取到的結果是由 Selector 組成的列表: SelectorList 。
它的類型是 scrapy.selector.unified.SelectorList
。
SelectorList 和 Selector 都可以繼續調用 xpath() 和 css() 等方法來進一步提取數據。
接着上面的例子,我們繼續嘗試獲取 a 標簽中的 img 標簽:
>>> result.xpath('./img')
[<Selector xpath='./img' data='<img src="image1_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image2_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image3_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image4_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image5_thumb.jpg">'>]
這里我們獲取到了所有的 a 標簽中的 img 標簽。
注意: 選擇器的最前方加 .
,這代表提取元素內部的數據,如果沒有加點,則代表從根節點開始提取。
此處我們用了./img
的提取方式,則代表從 a 節點里進行提取。如果此處我們用 //img
,則還是從 html 節點里進行提取。
現在我們已經獲得了 Selector 類型的節點 a ,如果我們想要將 a 節點元素提取出來,可以使用 extract()
方法,如下:
>>> result.extract()
['<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>',
'<a href="image2.html">Name: My image 2 <br><img src="image2_thumb.jpg"></a>',
'<a href="image3.html">Name: My image 3 <br><img src="image3_thumb.jpg"></a>',
'<a href="image4.html">Name: My image 4 <br><img src="image4_thumb.jpg"></a>',
'<a href="image5.html">Name: My image 5 <br><img src="image5_thumb.jpg"></a>']
這里我們如果想要獲得內容的文本內容,可以使用 /text()
,如果想要獲取 href 屬性的內容可以使用 /@href
。
我們來看一個完整的示例:
>>> response.xpath('//a[@href="image1.html"]/text()').extract()
['Name: My image 1 ']
這里我們限制的結果,只查到的一條數據,很多情況下我們都會獲得多條數據,這時如果想獲取第一個元素的內容,可以使用索引的方式,如下:
>>> response.xpath('//a/text()').extract()[0]
'Name: My image 1 '
這樣其實有一點點的小問題,如果當前我們需要的列表為空,這里直接會產生數組越界的異常。
Scrapy 為我們提供了另一個方法 extract_first()
,專門用來解決這個問題,上面的示例可以改寫成下面的樣子:
>>> response.xpath('//a/text()').extract_first()
'Name: My image 1 '
同時我們也可以為 extract_first() 方法設置一個默認值參數,這樣當 XPath 規則提取不到內容時會直接使用默認值。
>>> response.xpath('//a[@href="image1"]/text()').extract_first('Default')
'Default'
CSS 選擇器
我們接着看 CSS 選擇器,還是上面的示例,小編這里就不多 BB 了,直接上示例:
>>> response.css('a')
[<Selector xpath='descendant-or-self::a' data='<a href="image1.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image2.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image3.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image4.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image5.html">Name: My image ...'>]
我們同樣可以進行屬性選擇和嵌套選擇:
>>> response.css('a[href="image1.html"]').extract()
['<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>']
>>> response.css('a[href="image1.html"] img').extract()
['<img src="image1_thumb.jpg">']
接下來獲取文本值和屬性值的方法稍有區別:
>>> response.css('a[href="image1.html"]::text').extract()
['Name: My image 1 ']
>>> response.css('a[href="image1.html"] img::attr(src)').extract()
['image1_thumb.jpg']
獲取文本和屬性需要用 ::text
和 ::attr()
的寫法。
當然,我們的 CSS 選擇器和 Xpath 選擇器一樣可以嵌套選擇,一個簡單的小示例感受下:
>>> response.xpath('//a').css('img').xpath('@src').extract()
['image1_thumb.jpg', 'image2_thumb.jpg', 'image3_thumb.jpg', 'image4_thumb.jpg', 'image5_thumb.jpg']
Selector 選擇器就先介紹到這里了,更多的內容和用法可以參考官方文檔:https://docs.scrapy.org/en/latest/topics/selectors.html
本文沒什么代碼,所以示例代碼就不放了。