說明:文章是本人讀了崔慶才的Python3---網絡爬蟲開發實戰,做的簡單整理,希望能幫助正在學習的小伙伴~~
1. 准備工作:
安裝Scrapy框架、MongoDB和PyMongo庫,如果沒有安裝,google了解一下~~
2. 創建項目:
使用命令創建Scrapy項目,命令如下:
scrapy startproject tutorial
該命令可以在任意文件夾運行,如果提示權限問題,可以加sudo運行。該命令會創建一個名為tutorial的文件夾,結構如下:

# scrapy.cfg: Scrapy項目的配置文件,定義了項目的配置文件路徑,部署相關信息等
# item.py: 定義item數據結構(爬取的數據結構)
# pipeline.py: 定義數據管道
# settings.py: 配置文件
# middlewares.py: 定義爬取時的中間件
# spiders: 放置Spiders的文件夾
3. 創建Spider:
Spider是自己定義的類,Scrapy用它來從網頁抓取內容,並解析抓取結果。該類必須繼承Scrapy提供的Spider類scrapy.Spider。
使用命令創建一個Spider,命令如下:
cd tutorial
scrapy genspider quotes quotes.toscrape.com
首先,進入剛才創建的tutorial文件夾,然后執行genspider命令。第一個參數是spider的名稱,第二個參數是網絡域名(要抓取網絡的域名)。執行完畢后,spiders文件夾中多了一個quotes.py,它就是剛剛創建的Spider,內容如下:

該類中有三個屬性 ------ name、allowed_domains、start_urls,一個方法parse。
# name,唯一的名字,用來區分不同的Spider。
# allowed_domains,允許爬取的域名,如果初始或后續的請求鏈接不是該域名下的,則被過濾掉。
# start_urls,Spider在啟動時爬取的url列表,用來定義初始的請求。
# parse,它是spider的一個方法,用來處理start_urls里面的請求返回的響應,該方法負責解析返回的響應,提取數據或進一步生成處理的請求。
4. 創建Item:
Item是保存爬取數據的容器,使用方法和字典類似。創建Item需要繼承scrapy.Item類,並且定義類型為scrapy.Field的字段。
定義Item,將生成的items.py修改如下:

這里定義了三個字段,接下來爬取時我們會用到這個Item。
5. 解析Response:
前面我們看到,parse()方法的參數response是start_urls里面的鏈接爬取后的結果,所以在parse方法中,可以對response變量包含的內容進行解析。網頁結構如下:


提取方式可以是CSS選擇器或XPath選擇器。在這里,使用CSS選擇器,parse()方法修改如下:

首先,利用選擇器選取所有的quote,並將其賦值給quotes變量,然后利用for循環對每一個quote遍歷,解析每一個quote的內容。
對text來說,他的class是text,所以用.text選擇器來選取,這個結果實際上是整個帶有標簽的節點,要獲取它的正文內容,可以加::text來獲取。這時的結果是長度為1的列表,所以還需要用extract_first()方法來獲取第一個元素。
而對於tags來說,由於我們要獲取所有的標簽,所以用extract()方法來獲取整個列表即可。
6. 使用Item:
上面定義了Item,這邊我們就需要用到它。Item可以理解為一個字典,不過在這里需要先實例化,然后將解析的結果賦值給Item的每一個字段,最后返回Item。
修改QuotesSpider類如下:

至此,首頁的所有內容被解析出來了,並將結果賦值給一個個TutorialItem。
7. 后續Request:
上面實現了網頁首頁的抓取解析,那么下一頁怎么抓取呢?我們可以看到網頁的翻頁結構如下:


這里有一個Next按鈕,查看源碼,可以看出下一頁的全鏈接是:http://quotes.toscrape.com/page/2/,通過這個鏈接我們就可以構造下一個請求。
構造請求需要用到scrapy.Request。這里會有兩個參數 -------url和callback。
# url,請求鏈接。
# callback,回調函數。請求完畢后,獲取響應,引擎會將該響應作為參數傳遞給回調函數,回調函數進行解析或生成下一個請求。
在parse()方法中追加如下代碼:

第一句,獲取下一個頁面的鏈接,即要獲取a超鏈接中的href屬性。
第二句,調用urljoin()方法,urljoin()方法可以將相對URL構造成一個絕對URL。例如,獲取得到下一頁的地址是/page/2/,urljoin()方法處理后的結果是:http://quotes.toscrape.com/page/2/。
第三句,通過url和callback變量構造了一個新的請求,回調函數callback依然使用parse()方法。這樣,爬蟲就進入了一個循環,直到最后一頁。
修改之后,整個Spider類如下:

8. 運行:
進入目錄,運行如下命令:
scrapy crawl quotes
就可以看到Scrapy的運行結果了。
9. 保存到文件:
運行完Scrapy后,我們只在控制台看到了輸出結果。如何保存結果呢?
Scrapy提供了Feed Exports可以輕松將結果輸出。例如,我們想將上面的結果保存成JSON文件,可以執行如下命令:
scrapy crawl quotes -o quotes.json
命令運行后,會發現項目內多了一個quotes.json文件,這個文件包含了抓取的所有內容,格式為JSON。
另外,還支持其他格式如下:
scrapy crawl quotes -o quotes.jsonlines (scrapy crawl quotes -o quotes.jl , jl是jsonlines的縮寫)
scrapy crawl quotes -o quotes.csv
scrapy crawl quotes -o quotes.xml
scrapy crawl quotes -o quotes.pickle
scrapy crawl quotes -o quotes.marshal
scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quotes.csv (遠程輸出,需要正確配置,否則會報錯)
10. 使用Pipeline:
如果想進行復雜額操作,如將結果保存到MongoDB數據庫,或者篩選Item,我們可以定義Pipeline來實現。
前面提到,Pipeline是項目管道,當Item生成后,它會自動被送到Pipeline進行處理,主要的操作如下:
# 清理HTML數據
# 驗證爬取的數據,檢查爬取的字段
# 查重並丟棄重復內容
# 將結果保存到數據庫
實現Pipeline,只需要定義一個類並實現process_item()方法即可。啟用Pipeline后,Pipline會自動調用這個方法。process_item()方法必須返回包含數據的字典或item對象,或者拋出DropItem異常。
process_item()方法有兩個參數,一個參數是item,每次Spider生成的Item都會作為參數傳遞過來,另一個參數是spider,就是Spider的實例。
接下來,我們實現一個Pipline,篩掉text長度大於50的Item,並將結果保存到MongoDB數據庫。
修改pipelines.py如下:


# from_crawler,這是一個類方法,用@classmethod標識,是一種依賴注入。它的參數就是crawler,通過crawler可以拿到全局配置的每一個配置信息。在全局配置settings.py中,可以配置MONGO_UR和MONGO_DB來指定MongoDB連接需要的地址和數據庫名稱,拿到配置信息之后返回類對象即可。所以這個方法主要是用來獲取settings.py中的配置信息。
# open_spider,當Spider開啟時,這個方法被調用。進行初始化操作。
# close_spider,當Spider關閉時,這個方法被調用。將數據庫連接關閉。
最主要的process_item()方法則進行了數據插入操作。
定義好的TutorialPipeline和MongoPipline這兩個類后,我們需要在settings.py中使用它們,MongoDB的連接信息也需要在settings.py中定義。
settings.py中加入如下內容:

賦值ITEM_PIPELINES字典,鍵名是Pipeline的類名稱,鍵值是調用的優先級,是一個數字,數字越小對應的Pipeline越先被調用。
重新執行如下命令進行爬取:
scrapy crawl quotes
結束后,MongoDB中會創建了一個tutorial的數據庫、TutorialItem的表,如下圖:

11. 結語:
至此,一個簡單的Scrapy框架爬蟲就完成了,這只是一個簡單的爬蟲例子,想要了解更多,可以去看看崔慶才的書---------《Python3 網絡爬蟲開發實戰》。
Github上面也有許多相關的項目可以去研究~~~
