您好,登錄后才能下訂單哦!
小編給大家分享一下關(guān)于Python3爬蟲中Selector的用法,相信大部分人都還不怎么了解,因此分享這篇文章給大家學(xué)習(xí),希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去學(xué)習(xí)方法吧!
Selector 的用法
我們之前介紹了利用 Beautiful Soup、pyquery 以及正則表達(dá)式來提取網(wǎng)頁數(shù)據(jù),這確實非常方便。而 Scrapy 還提供了自己的數(shù)據(jù)提取方法,即 Selector(選擇器)。Selector 是基于 lxml 來構(gòu)建的,支持 XPath 選擇器、CSS 選擇器以及正則表達(dá)式,功能全面,解析速度和準(zhǔn)確度非常高。
本節(jié)將介紹 Selector 的用法。
1. 直接使用
Selector 是一個可以獨立使用的模塊。我們可以直接利用 Selector 這個類來構(gòu)建一個選擇器對象,然后調(diào)用它的相關(guān)方法如 xpath()、css() 等來提取數(shù)據(jù)。
例如,針對一段 HTML 代碼,我們可以用如下方式構(gòu)建 Selector 對象來提取數(shù)據(jù):
from scrapy import Selector body = '<html><head><title>Hello World</title></head><body></body></html>' selector = Selector(text=body) title = selector.xpath('//title/text()').extract_first() print(title)
運(yùn)行結(jié)果:
Hello World
我們在這里沒有在 Scrapy 框架中運(yùn)行,而是把 Scrapy 中的 Selector 單獨拿出來使用了,構(gòu)建的時候傳入 text 參數(shù),就生成了一個 Selector 選擇器對象,然后就可以像前面我們所用的 Scrapy 中的解析方式一樣,調(diào)用 xpath()、css() 等方法來提取了。
在這里我們查找的是源代碼中的 title 中的文本,在 XPath 選擇器最后加 text() 方法就可以實現(xiàn)文本的提取了。
以上內(nèi)容就是 Selector 的直接使用方式。同 Beautiful Soup 等庫類似,Selector 其實也是強(qiáng)大的網(wǎng)頁解析庫。如果方便的話,我們也可以在其他項目中直接使用 Selector 來提取數(shù)據(jù)。
接下來,我們用實例來詳細(xì)講解 Selector 的用法。
2. Scrapy Shell
由于 Selector 主要是與 Scrapy 結(jié)合使用,如 Scrapy 的回調(diào)函數(shù)中的參數(shù) response 直接調(diào)用 xpath() 或者 css() 方法來提取數(shù)據(jù),所以在這里我們借助 Scrapy shell 來模擬 Scrapy 請求的過程,來講解相關(guān)的提取方法。
我們用官方文檔的一個樣例頁面來做演示:http://doc.scrapy.org/en/latest/_static/selectors-sample1.html。
開啟 Scrapy shell,在命令行輸入如下命令:
scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
我們就進(jìn)入到 Scrapy shell 模式。這個過程其實是,Scrapy 發(fā)起了一次請求,請求的 URL 就是剛才命令行下輸入的 URL,然后把一些可操作的變量傳遞給我們,如 request、response 等,如圖 13-5 所示。
圖 13-5 Scrapy Shell
我們可以在命令行模式下輸入命令調(diào)用對象的一些操作方法,回車之后實時顯示結(jié)果。這與 Python 的命令行交互模式是類似的。
接下來,演示的實例都將頁面的源碼作為分析目標(biāo),頁面源碼如下所示:
<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>
3. XPath 選擇器
進(jìn)入 Scrapy shell 之后,我們將主要操作 response 這個變量來進(jìn)行解析。因為我們解析的是 HTML 代碼,Selector 將自動使用 HTML 語法來分析。
response 有一個屬性 selector,我們調(diào)用 response.selector 返回的內(nèi)容就相當(dāng)于用 response 的 text 構(gòu)造了一個 Selector 對象。通過這個 Selector 對象我們可以調(diào)用解析方法如 xpath()、css() 等,通過向方法傳入 XPath 或 CSS 選擇器參數(shù)就可以實現(xiàn)信息的提取。
我們用一個實例感受一下,如下所示:
>>> result = response.selector.xpath('//a') >>> result [<Selector xpath='//a' data='<a href="image1.html">Name: My image 1 <'>, <Selector xpath='//a' data='<a href="image2.html">Name: My image 2 <'>, <Selector xpath='//a' data='<a href="image3.html">Name: My image 3 <'>, <Selector xpath='//a' data='<a href="image4.html">Name: My image 4 <'>, <Selector xpath='//a' data='<a href="image5.html">Name: My image 5 <'>] >>> type(result) scrapy.selector.unified.SelectorList
打印結(jié)果的形式是 Selector 組成的列表,其實它是 SelectorList 類型,SelectorList 和 Selector 都可以繼續(xù)調(diào)用 xpath() 和 css() 等方法來進(jìn)一步提取數(shù)據(jù)。
在上面的例子中,我們提取了 a 節(jié)點。接下來,我們嘗試?yán)^續(xù)調(diào)用 xpath() 方法來提取 a 節(jié)點內(nèi)包含的 img 節(jié)點,如下所示:
>>> 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 節(jié)點里面的所有 img 節(jié)點,結(jié)果為 5。
值得注意的是,選擇器的最前方加 .(點),這代表提取元素內(nèi)部的數(shù)據(jù),如果沒有加點,則代表從根節(jié)點開始提取。此處我們用了./img 的提取方式,則代表從 a 節(jié)點里進(jìn)行提取。如果此處我們用 //img,則還是從 html 節(jié)點里進(jìn)行提取。
我們剛才使用了 response.selector.xpath() 方法對數(shù)據(jù)進(jìn)行了提取。Scrapy 提供了兩個實用的快捷方法,response.xpath() 和 response.css(),它們二者的功能完全等同于 response.selector.xpath() 和 response.selector.css()。方便起見,后面我們統(tǒng)一直接調(diào)用 response 的 xpath() 和 css() 方法進(jìn)行選擇。
現(xiàn)在我們得到的是 SelectorList 類型的變量,該變量是由 Selector 對象組成的列表。我們可以用索引單獨取出其中某個 Selector 元素,如下所示:
>>> result[0] <Selector xpath='//a' data='<a href="image1.html">Name: My image 1 <'>
我們可以像操作列表一樣操作這個 SelectorList。
但是現(xiàn)在獲取的內(nèi)容是 Selector 或者 SelectorList 類型,并不是真正的文本內(nèi)容。那么具體的內(nèi)容怎么提取呢?
比如我們現(xiàn)在想提取出 a 節(jié)點元素,就可以利用 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>']
這里使用了 extract() 方法,我們就可以把真實需要的內(nèi)容獲取下來。
我們還可以改寫 XPath 表達(dá)式,來選取節(jié)點的內(nèi)部文本和屬性,如下所示:
>>> response.xpath('//a/text()').extract() ['Name: My image 1 ', 'Name: My image 2 ', 'Name: My image 3 ', 'Name: My image 4 ', 'Name: My image 5 '] >>> response.xpath('//a/@href').extract() ['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
我們只需要再加一層 /text() 就可以獲取節(jié)點的內(nèi)部文本,或者加一層 /@href 就可以獲取節(jié)點的 href 屬性。其中,@符號后面內(nèi)容就是要獲取的屬性名稱。
現(xiàn)在我們可以用一個規(guī)則把所有符合要求的節(jié)點都獲取下來,返回的類型是列表類型。
但是這里有一個問題:如果符合要求的節(jié)點只有一個,那么返回的結(jié)果會是什么呢?我們再用一個實例來感受一下,如下所示:
>>> response.xpath('//a[@href="image1.html"]/text()').extract() ['Name: My image 1 ']
我們用屬性限制了匹配的范圍,使 XPath 只可以匹配到一個元素。然后用 extract() 方法提取結(jié)果,其結(jié)果還是一個列表形式,其文本是列表的第一個元素。但很多情況下,我們其實想要的數(shù)據(jù)就是第一個元素內(nèi)容,這里我們通過加一個索引來獲取,如下所示:
python>>> response.xpath('//a[@href="image1.html"]/text()').extract()[0] 'Name: My image 1 '
但是,這個寫法很明顯是有風(fēng)險的。一旦 XPath 有問題,那么 extract() 后的結(jié)果可能是一個空列表。如果我們再用索引來獲取, 那不就會可能導(dǎo)致數(shù)組越界嗎? 所以,另外一個方法可以專門提取單個元素,它叫作 extract_first()。我們可以改寫上面的例子如下所示: ```python >>> response.xpath('//a[@href="image1.html"]/text()').extract_first() 'Name: My image 1 '
這樣,我們直接利用 extract_first() 方法將匹配的第一個結(jié)果提取出來,同時我們也不用擔(dān)心數(shù)組越界的問題。
另外我們也可以為 extract_first() 方法設(shè)置一個默認(rèn)值參數(shù),這樣當(dāng) XPath 規(guī)則提取不到內(nèi)容時會直接使用默認(rèn)值。例如將 XPath 改成一個不存在的規(guī)則,重新執(zhí)行代碼,如下所示:
>>> response.xpath('//a[@href="image1"]/text()').extract_first()>>> response.xpath('//a[@href="image1"]/text()'). extract_first('Default Image') 'Default Image'
這里,如果 XPath 匹配不到任何元素,調(diào)用 extract_first() 會返回空,也不會報錯。
在第二行代碼中,我們還傳遞了一個參數(shù)當(dāng)作默認(rèn)值,如 Default Image。這樣如果 XPath 匹配不到結(jié)果的話,返回值會使用這個參數(shù)來代替,可以看到輸出正是如此。
現(xiàn)在為止,我們了解了 Scrapy 中的 XPath 的相關(guān)用法,包括嵌套查詢、提取內(nèi)容、提取單個內(nèi)容、獲取文本和屬性等。
4. CSS 選擇器
接下來,我們看看 CSS 選擇器的用法。
Scrapy 的選擇器同時還對接了 CSS 選擇器,使用 response.css() 方法可以使用 CSS 選擇器來選擇對應(yīng)的元素。
例如在上文我們選取了所有的 a 節(jié)點,那么 CSS 選擇器同樣可以做到,如下所示:
>>> response.css('a') [<Selector xpath='descendant-or-self::a' data='<a href="image1.html">Name: My image 1 <'>, <Selector xpath='descendant-or-self::a' data='<a href="image2.html">Name: My image 2 <'>, <Selector xpath='descendant-or-self::a' data='<a href="image3.html">Name: My image 3 <'>, <Selector xpath='descendant-or-self::a' data='<a href="image4.html">Name: My image 4 <'>, <Selector xpath='descendant-or-self::a' data='<a href="image5.html">Name: My image 5 <'>]
同樣,調(diào)用 extract() 方法就可以提取出節(jié)點,如下所示:
python>>> response.css(‘a(chǎn)’).extract() [‘Name: My image 1 ‘, ‘Name: My image 2 ‘, ‘Name: My image 3 ‘, ‘Name: My image 4 ‘, ‘Name: My image 5 ‘]
用法和 XPath 選擇是完全一樣的。 另外,我們也可以進(jìn)行屬性選擇和嵌套選擇,如下所示: ```python >>> 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">'] ```這里用 [href="image.html"] 限定了 href 屬性,可以看到匹配結(jié)果就只有一個了。另外如果想查找 a 節(jié)點內(nèi)的 img 節(jié)點, 只需要再加一個空格和 img 即可。選擇器的寫法和標(biāo)準(zhǔn) CSS 選擇器寫法如出一轍。 我們也可以使用 extract_first() 方法提取列表的第一個元素,如下所示: ```python >>> response.css('a[href="image1.html"] img').extract_first() '<img src="image1_thumb.jpg">'
接下來的兩個用法不太一樣。節(jié)點的內(nèi)部文本和屬性的獲取是這樣實現(xiàn)的,如下所示:
>>> response.css('a[href="image1.html"]::text').extract_first() 'Name: My image 1 ' >>> response.css('a[href="image1.html"] img::attr(src)').extract_first() 'image1_thumb.jpg'
獲取文本和屬性需要用::text 和::attr() 的寫法。而其他庫如 Beautiful Soup 或 pyquery 都有單獨的方法。
另外,CSS 選擇器和 XPath 選擇器一樣可以嵌套選擇。我們可以先用 XPath 選擇器選中所有 a 節(jié)點,再利用 CSS 選擇器選中 img 節(jié)點,再用 XPath 選擇器獲取屬性。我們用一個實例來感受一下,如下所示:
>>> response.xpath('//a').css('img').xpath('@src').extract() ['image1_thumb.jpg', 'image2_thumb.jpg', 'image3_thumb.jpg', 'image4_thumb.jpg', 'image5_thumb.jpg']
我們成功獲取了所有 img 節(jié)點的 src 屬性。
因此,我們可以隨意使用 xpath() 和 css() 方法二者自由組合實現(xiàn)嵌套查詢,二者是完全兼容的。
5. 正則匹配
Scrapy 的選擇器還支持正則匹配。比如,在示例的 a 節(jié)點中的文本類似于 Name: My image 1,現(xiàn)在我們只想把 Name: 后面的內(nèi)容提取出來,這時就可以借助 re() 方法,實現(xiàn)如下:
>>> response.xpath('//a/text()').re('Name:s(.*)') ['My image 1 ', 'My image 2 ', 'My image 3 ', 'My image 4 ', 'My image 5 ']
我們給 re() 方法傳了一個正則表達(dá)式,其中 (.*) 就是要匹配的內(nèi)容,輸出的結(jié)果就是正則表達(dá)式匹配的分組,結(jié)果會依次輸出。
如果同時存在兩個分組,那么結(jié)果依然會被按序輸出,如下所示:
>>> response.xpath('//a/text()').re('(.*?):s(.*)') ['Name', 'My image 1 ', 'Name', 'My image 2 ', 'Name', 'My image 3 ', 'Name', 'My image 4 ', 'Name', 'My image 5 ']
類似 extract_first() 方法,re_first() 方法可以選取列表的第一個元素,用法如下:
>>> response.xpath('//a/text()').re_first('(.*?):s(.*)') 'Name' >>> response.xpath('//a/text()').re_first('Name:s(.*)') 'My image 1'
不論正則匹配了幾個分組,結(jié)果都會等于列表的第一個元素。
值得注意的是,response 對象不能直接調(diào)用 re() 和 re_first() 方法。如果想要對全文進(jìn)行正則匹配,可以先調(diào)用 xpath() 方法再正則匹配,如下所示:
>>> response.re('Name:s(.*)') Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'HtmlResponse' object has no attribute 're' >>> response.xpath('.').re('Name:s(.*)<br>') ['My image 1 ', 'My image 2 ', 'My image 3 ', 'My image 4 ', 'My image 5 '] >>> response.xpath('.').re_first('Name:s(.*)<br>') 'My image 1'
通過上面的例子,我們可以看到,直接調(diào)用 re() 方法會提示沒有 re 屬性。但是這里首先調(diào)用了 xpath(‘.’) 選中全文,然后調(diào)用 re() 和 re_first() 方法,就可以進(jìn)行正則匹配了。
以上是關(guān)于Python3爬蟲中Selector的用法的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。