Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

環境準備:

  1. 使用pip安裝lxml和scrapy
  2. scrapy startproject amazon_comment創建一個名為amazon_comment的scrapy爬蟲項目

scrapy核心工作流程:

  1. scrapy.spiders.Spider中,有個變量start_urls,是數組類型,表示我們需要讓爬蟲從哪些鏈接開始爬取。Spider會以start_urls中的鏈接,生成一個含有默認回調函數parse的Request,然後使用該鏈接發出HTTP請求,獲取到HTTP響應內容,封裝成Response對象,然後把該Response對象作為參數傳遞給回調函數parse。Spider中最開始的Request是通過調用start_requests()方法來獲取的,start_requests()方法是Spider默認實現好的,我們一般不用去實現這個方法。在start_requests()方法中,是通過讀取start_urls中的鏈接,默認的以parse作為回調函數生成Request請求的。
  2. 當獲取到Response對象之後,我們可以覆蓋回調函數:parse方法,也可以在生成Request指定我們想要的任何回調函數。這樣,Response就會作為參數傳入我們指定的回調函數里面了(默認是parse方法)。然後,我們可以在我們設置的回調函數里面,從Response對象解析出返回的網頁header內容,網頁body內容。最常見的就是使用scrapy提供的scrapy.selector.Selector來從網頁body中提取出我們想要的網頁內容。我們設置的回調函數可以返回一個Item對象,或者是一個dict,或者是Request對象,或者是一個包括這三個東西的可迭代對象。在使用Selector提取網頁內容時,最常見的就是使用xpath語法來定位和提取網頁中我們想要的數據。
  3. 如果回調函數返回的是Request對象,那麼這個Request對象之後又會經過Scrapy處理(發請求,獲取Response,傳遞給回調函數處理)。
  4. 如果我們設置的回調函數返回的是Item對象,那麼scrapy會把該Item傳遞給scrapy中我們定義好的 Item Pipeline處理,所以,我們一般都要實現ItemPipeline,最常見的是在Item Pipeline中把Item對象格式化成我們想要的格式,然後持久化到數據庫中。


Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

當我們實現scrapy.spiders.Spider時:

如果是不需要登錄,不需要設置header的,只通過一個url就能訪問的網頁,那麼在scrapy.spiders的Spider類中,重寫parse(response)方法即可。

如果是不需要登錄,需要設置header的(一般設置User-Agent和Referer),通過url就能訪問的網頁,那麼重寫parse(response)方法,然後在scrapy.spiders的Spider類中,重寫start_requests()方法,在該方法中返回一個設置了headers參數的scrapy.http.Request對象即可。該Request對象還可以設置callback,如果設置了callback,該start_requests方法返回該Request對象後,scrapy內部會根據該Request發出請求,獲取scrapy.http.Response對象,然後把Response對象傳遞給該callback方法作參數,然後執行該callback方法;如果沒有設置callback,那麼scrapy內部會根據該Request發出請求,獲取scrapy.http.Response對象,然後把Response對象傳遞給parse方法作參數,然後執行parse方法。

如果是需要登錄,需要設置header的,通過url訪問的網頁,那麼可以在start_urls中第一個元素設置為登錄的url,然後在start_requests()方法中,返回一個設置了formdata參數的

scrapy.FormRequest對象。該FormRequest是繼承自scrapy.http.Request對象的,FormRequest沒有設置額外必需的位置參數,提供了可選參數formdata,當formdata不為None時,method必為POST(FormRequest的__init__方法會自動設置)。FormRequest顯然可以當做Request使用。所有Request的默認的回調函數是parse(response)方法,設置了另外的回調函數的話,該parse方法不會被調用。


scrapy核心方法:scrapy.spiders.Spider.start_requests():

上面提到,scrapy在開始工作時會以執行start_requests()方法,該方法中會以start_urls變量中的鏈接來創建Request,從而下載網頁。我們來看一下start_requests()方法的默認實現。

該方法的默認實現為,

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

通常把該方法實現為一個生成器(包含yield的函數),因為我們會在start_urls中存儲我們想爬取的url,對於start_urls中的每一個url的處理,該方法只會調用一次(並不是在該項目的整個爬取過程中只調用一次,而是對於每個url只調用一次),然後調用回調函數處理Response從而獲取item。

所以如果我們重寫了這個方法,那麼我們一般也將它實現為生成器,即在yield中通過make_requests_from_url(url)方法返回默認的Request對象。例如,

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

scrapy.spiders.Spider中該方法的默認實現會從start_urls中取url來生成scrapy.http.Request,我們在該方法中也可以不使用start_urls而是自己隨意使用url生成Request返回。

Request的必備參數只有一個,如Request的構造方法為,

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

Request的構造方法

FormRequest

在一個網頁需要登錄或者提交表單數據才能訪問時,我們可以不使用默認的Request而是FormRequest。FormRequest從名字上就可以看出,就是為了在請求中模擬表單請求而存在的。

scrapy.FormRequest繼承自Request,無額外的必備參數,可以設置formdata參數來使用POST提交數據。

如,

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

scrapy核心方法:scrapy.spiders.Spider.parse(response):

parse方法是scrapy.http.Request中默認的回調函數,在Request中我們如果不顯式聲明回調函數的話,Request會默認把parse方法作為回調函數使用。

parse方法必須返回一個包含scrapy.http.Request對象、dict、project.items中定義的Item的可迭代的對象(一般實現為生成器,即在方法最後使用yield item或者yield Request)。

parse方法如果返回scrapy.http.Request對象,則scrapy內部還會通過該Request對象獲取scrapy.http.Response,然後傳遞給該Request中的回調函數並調用該回調函數(默認是parse方法)。

parse方法中可以使用自定義的任何解析器來分析Response,獲取item(一般是使用xpath,即scrapy.selector.Selector.xpath()方法,該方法還是返回一個Selector對象)。如

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

parse方法中提取想要的數據:scrapy.selector.Selector和xpath:

在parse方法中,要從抓取的網頁提取感興趣的數據,需要使用到Selector和xpath。

Selector構造函數為:

Selector(response=None, text=None, type=None, namespaces=None, _root=None, _expr=None)

Selector常用方法為:

  1. extract():返回Selector對象的unicode字符串列表。
  2. extract_first():返回Selector對象匹配到的第一個元素。
  3. xpath():返回一個Selector對象

Selector和xpath使用示例:

  1. Selector(response).xpath('//span/text()').extract(): # 以列表方式返回所有span元素的文本內容。
  2. Selector(response).xpath('//div[@id]/a[1]/text()').extract(): # @表示選取屬性,該句表示以列表形式返回所有具有id屬性的div中第一個超鏈接的文本內容。或者使用Selector(response).xpath('//div[@id]/a/text()').extract_first()Selector(response).xpath('//div[@id and @class]/a/text()').extract(): # 多個條件用and連接
  3. Selector(response).xpath('//div[@id="images"]/a[1]/text()').extract(): # @表示選取屬性,該句表示以列表形式返回所有id為images的div中第一個超鏈接的文本內容。
  4. Selector(response).xpath('//div[ul]/a/text()').extract(): # 以列表形式返回所有含有ul子元素的div中所有超鏈接的文本內容。
  5. Selector(response).xpath('//div[last()]/a/text()').extract(): # 以列表形式返回最後一個div中所有超鏈接的文本內容。
  6. Selector(response).xpath('//a[contains(@href, "image")]/@href').extract(): # 以列表形式返回所有的超鏈接中,其href屬性包含"image"內容的那些超鏈接的鏈接內容。 這樣的鏈接會被匹配上,因為href屬性包含"image"內容。
  7. element_dom.xpath("//div[@class='item_list']//li/a/@href"): # 選取任意位置的class為item_list的div節點的全部子節點li【div後代節點,不管在div中任何位置】中a節點的href屬性

xpath鏈式寫法、條件嵌套和多條件查找:

xpath()完之後,仍然可以繼續xpath:

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

注意:xpath鏈式寫法重複利用時,'//'前需要加上點'.'。如在某個xpath對象下繼續使用xpath規則提取, 當提取某個對象下的所有某個對象所有tr標籤:

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

xpath多條件查找:

假設xml內容為下圖,我們想要查找包含“data”節點並且“data”的type屬性為"String"並且“data”節點的文本為“Alpha”的所有“cell”節點(即下圖中的第一個data節點):

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

滿足需求的xpath為://cell[data[text()='Alpha'] and data[@type='String']] 或 //cell[data[text()='Alpha' and @type='String']]。//cell表示搜索所有的cell節點,中括號[]裡面是條件,滿足了中括號中所有條件的cell節點會被搜索出來,data[text()='Alpha' and @type='String']表示(節點文本="Alpha"且type="String")的子節點會被搜索出來。其中,中括號中的多個條件用and連接,相當於Python條件表達式中的and語法。

如果要在加一層結點的話,則中括號[]繼續嵌套,想要查找子孫節點為data節點並且該data節點的type屬性為"String"並且data節點的文本為“Alpha”的所有Row結點:

Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

滿足條件的xpath為://row[cell/data[text()='Alpha'] and cell/data[@type='String']] 或 //row[cell/data[text()='Alpha' and @type='String']]

Selector().css()

與xpath類似,我們也可以在Selector上使用css()方法來查找元素。

css()方法:返回一個Selector對象,採用css語法來查找元素。

css()示例:

  1. Selector(response).css('title::text').extract() # 以列表方式返回所有title元素的文本內容。
  2. Selector(response).css('base::attr(href)').extract() # 以列表方式返回所有base元素的href屬性內容。
  3. Selector(response).css('a[href*=image]::attr(href)').extract() # 以列表方式返回所有超鏈接中,href屬性包含"image"的那些超鏈接的鏈接內容。
  4. Selector(response).css('a[href*=asks] .num::text').extract() # 以列表方式返回所有超鏈接中,href屬性包含"asks"的那些超鏈接下,class為num的那些元素的文本內容。


Python爬蟲之Scrapy爬蟲框架解密與並爬取亞馬遜評論數據

更多文章


喜歡的可以關注,讚賞多多支持一下!


分享到:


相關文章: