1. 程式人生 > >Scrapy爬蟲----(二)專案實戰(上)

Scrapy爬蟲----(二)專案實戰(上)

結合上一篇博文《Scrapy爬蟲—-(一)命令列工具》中講解的一些常用的命令我們可以很方便的建立一個Scrapy專案,這篇文章便可以開始我們的第一個Scrapy爬蟲專案:爬取一個簡單的靜態網頁中的小說內容:http://yetianlian.com

一、專案目錄結構

下圖便是我們利用上一篇文章中的兩個命令建立的scrpay專案目錄結構以及檔案介紹 :

scrapy專案目錄結構

二、專案目標

這裡專案是從開始爬取一個簡單的靜態網頁入手:http://www.yetianlian.com/ (這個靜態網頁涉及到的反爬蟲策略較少,方便新手學習)專案的目的是獲取下圖中文章中的標題,章節標題,每一小節的標題以及每一小節的小說內容最終以“小節名.txt”檔案格式存入按以上標題級別建立的檔案目錄下。

網頁內容
檔案目錄以及檔案圖示:
檔案目錄
檔案圖示

三、分析與實現

想實現最終的目標,我們第一步要做的是確定我們要爬取的內容是那些,定義在items.py檔案中,然後在ytl.py檔案中編寫parse方法, 利用pipelines.py檔案對資料進行處理,最後修改settings.py檔案,其中每一個步驟都不能遺漏,最後執行crawl spider命令便可以按照我們所需要的內容對網頁解析原始碼,抓取資料,儲存資料。

3.1 ytl.py

首先進入spiders資料夾下檢視ytl.py自動生成的spider程式碼
爬蟲模組的程式碼都放置在這個資料夾中,爬蟲模組是用於從單個或者多個網站爬取資料的類。其中應該包括有初始頁面的URL,跟進的網頁連結,分析頁面內容,提取需要的資料函式。建立一個Spider類需要繼承scrapy.Spider類,其中定義有一下三個屬性:name,allowed_domains,start_urls,具體屬性的介紹在下面的程式碼的註釋部分體現:

ytl.py原始碼:

class YtlSpider(scrapy.Spider):
    # 爬蟲的唯一名字,不能為不同的spider設定相同的名字
    name = 'ytl'
    # 爬蟲允許爬取URL的域名範圍,這個爬蟲允許的爬取的範圍為yetianlian.com
    allowed_domains = ['yetianlian.com']
    # start_urls 是spider在啟動時進行爬取的入口的URL列表。因此,第一個被獲取的URL也是其中之一
    # 後續的URL則會從初始的URL的響應中主動提取
    start_urls = ['http://yetianlian.com'
] # parse() 函式,是spider的一個方法。被呼叫時,根據初始的URL響應後的返回的Response物件 # 將會作為唯一的引數傳遞給該方法。該方法有三個功能 # (1.解析返回的資料(response data) 2.提取資料(生成item) 3.生成需要進一步處理的URL的Request物件) def parse(self, response): # pass是空語句,是為了保持程式結構的完整性。pass 不做任何事情,一般用做佔位語句 pass

3.2 Items.py

我們根據所要獲取內容,可以再item中建立這些fields:chapternum、chaptername、chapterurl、chaptercontent。

Items.py原始碼:

class Testdemo001Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    # 跟進的文章連結
    url = scrapy.Field()
    # 內部第幾章
    chapternum = scrapy.Field()
    # 該章節的名稱
    chaptertitle = scrapy.Field()
    # 該章節的url
    chapterurl = scrapy.Field()
    # 該章節的內容
    chaptercontent = scrapy.Field()

    pass

Item知識:

Item的目的是提供了一個方便讓爬取的資料從非結構性的資料來源提取結構性資料的簡單容器,可以用來儲存爬取到的資料,提供了類似於字典API以及用於宣告可用欄位的簡單語法。我們定義的Item類需要繼承scrapy.Item類,具體的程式碼如上。

Item的操作方式和字典很類似,這裡講常用的幾個操作簡單介紹:
建立物件:item = Testdemo001Item(title = ‘XXXX’, content = ‘XXX’)
獲取欄位的值:a = item[‘title’]
設定欄位的值:item[‘title’] = ‘XXX’
獲取所有鍵,值:item.keys(),item.values()
獲取item中所有的key以及key對應的值:item.items()
dict與item轉化:dict_item = dict(item)
Testdemo001Item可以被繼承,可以新增更多的欄位

3.3 ytl.py—(parse方法)

預設生成的spider檔案中沒有提供特殊的功能,僅僅提供了start_request()的預設實現,可以讀取並請求spider屬性中的start_urls,並根據返回的response呼叫spider的parse方法。上面完成了網頁下載的功能,接下來需要做的工作即是提取網頁中的資料:從網頁中提取我們需要的chapternum、chaptername、chapterurl、chaptercontent,然後將這些內容封裝成Item物件以便於後續的儲存操作。

網頁資料提取:

在1板塊中的ytl.py檔案建立後,我們執行crawl spidername爬蟲命令可以實現對網頁下載的功能,僅有網頁下載的功能我們無法獲取所需要的資料,接下來是對網頁資料的提取。

Scrapy有著自己的一套對於網頁資料提取的機制,稱為選擇器selector(點選可以檢視官方介紹),可以用selector通過特定的XPath和CSS表示式來選擇HTML檔案中的某個部分。scrapy選擇器是建立在lxml解析庫上,這意味scrapy在速度和解析準確度上比較的優秀。當然,我們也可以使用BeautifulSoup包進行解析,後面的文章會詳細介紹Phantomjs+BeautifulSoup建立的爬蟲。

Selector物件有四個基本方法:

xpath(query):傳入XPath表示式query,返回該表示式所對應的所有節點的selector list 列表

css(query):傳入CSS表示式query,返回該表示式所對應的所有節點的selector list 列表

extract()[]:序列化該節點為Unicode字串並返回list列表,[n]可以精確定位返回的第n個字串(從0開始索引,第0個字串……)

re(regex):根據傳入的正則表示式對資料進行提取,返回Unicode字串列表。這裡regex表示的是根據語法寫的正則表示式。另外也可以使用re.compile(regex),官方給出具體的解釋如下:regex can be either a compiled regular expression or a string which will be compiled to a regular expression using re.compile(regex) 【re模組中包含一個重要函式是compile(pattern [, flags]) ,該函式根據包含的正則表示式的字串建立模式物件。可以實現更有效率的匹配。在直接使用字串表示的正則表示式進行search,match和findall操作時,python會將字串轉換為正則表示式物件。而使用compile完成一次轉換之後,在每次使用模式的時候就不用重複轉換。當然,使用re.compile()函式進行轉換後,re.search(pattern, string)的呼叫方式就轉換為 pattern.search(string)的呼叫方式。】

而在YtlSpider類的parse()方法中,其中一個引數是response,將response傳入selector中,便可以直接構造出一個Selector物件,進而可以呼叫以上的四個方法。寫法可以使response.selector.xpath(query)一般使用簡寫的方式response.xpath(query),或者response.xpath(query)的形式。我們可以使用scarpy shell url來檢測我們所獲取的xpath或者css等是否正確,這裡在上一篇文章中有介紹,這裡不再贅述。如果對於xpath和regex(正則表示式)不是很清楚,後面的部落格中會介紹關於xpath和regex部分。

網頁分析:

這裡使用的是GoogleChrome瀏覽器對網頁進行F12檢視元素(FireFox最新的版本已經關閉firebug和firepath等外掛的使用,大部分功能均集中到Firefox Developer Edition版本中,考慮到版本不穩定,文章中採用的均是Chrome檢視網頁原始碼)
可以使用ctl+shift+c快捷鍵開始審查元素的功能,這裡可以看到我們需要的內容所在網頁對應的原始碼部分,選中該元素右鍵可以copy該元素的xpath(若是對於一個元素的獲取,我們可以直接使用這個xpath,若是同類的元素,我們需要稍微修改一下xpath即可)
審查元素
點選每一章節開啟後的網頁便是每一個章節小說的具體內容,我們可以使用同樣的方法,獲取小說內容在網頁中所對應的原始碼部分

資料提取:

我們通過selector選擇器和xpath來獲取我們需要的內容,可以再ipython中檢視我們所用的xpath是否正確

標題元素獲取

圖中第一個使用firefox自帶的開發者工具審查元素獲取的xpath,可以看出,是一個完整的路徑,對於我們要獲取相同元素的xpath修改不方便,第二個是chrome審查元素獲取的xpath,比較符合xpath的書寫,也便於我們後面的修改,一般都以後者書寫。
標題的獲取

副標題的xpath,我們可以根據//[@id=”post-1135”]/div/h3/text()進行修改為//[@id=”post-1135”]/div/h2/text()或者//*[@id=”post-1135”]//h2/text(),然後可以在scrapy shell下檢測是否正確
子標題選擇
可以看出子標題一共有三個,我們選擇出來四個,說明多了一個,檢視原始碼可以看出來,上面有一個標題和下面三個子標題xpath路徑規則一樣
網頁原始碼

我們可以採用extract()[]精確的獲取我們需要的部分,其中的操作和python中list的用法一樣,從‘0’開始索引,‘-1’表示結尾,[0:n]表示list中的第0個元素到第n-1個元素(不包括第n個元素),[-1]表示從list結尾開始數,倒數第一個元素,[-n]表示倒數第n個元素:
子標題獲取

另外的幾個部分也可按照同樣的思路進行對網頁的資料進行提取
在完成以上的任務之後,我們開始可以著手parse()方法,方法的目的:從網頁中提取出我們需要的資料內容,然後封裝成Item物件,方便下一步的進行

結語:

文章的內容均是博主碼字上去的,在閱讀的過程中如果遇到有問題請指出,若對文章中的內容如有不同的見解,歡迎一起學習討論。