scrapy-redis介紹(一)

scrapy是python裏面一個非常完善的爬蟲框架,實現了非常多的功能,比如內存檢測,對象引用查看,命令行,shell終端,還有各種中間件和擴展等,相信開發過scrapy的朋友都會覺得這個框架非常的強大。但是它有一個致命的缺點,不支持分佈式。所以本文介紹的是scrapy_redis,繼承了scrapy的所有優點,還支持分佈式。

1.安裝scrapy

安裝scrapy非常簡單:

sudo pip install scrapy
sudo pip install scrapy_redis

#如果下載的不順利,可以試試這樣,換一個國內的源,下載速度會飆升
sudo pip install --index https://pypi.mirrors.ustc.edu.cn/simple/ scrapy

在這裏建議開發scrapy_redis使用python 2.7版本,雖然也支持3.x,但總覺得會出bug.

安裝完成,選擇一個恰當的目錄,並進入那個目錄,運行構建項目的命令行即可自動爲我們創建一個spider目錄:

scrapy startproject myspider

簡單的一行即可完成。scrapy有非常多的命令行,大家自行去查詢官方文檔。

2.scrapy_redis原理

scrapy-redis原理:
1.spider解析下載器下載下來的response,返回item或者是links
2.item或者links經過spidermiddleware的process_spider_out()方法,交給engine。
3.engine將item交給itempipeline,將links交給調度器
4.在調度器中,先將request對象利用scrapy內置的指紋函數,生成一個指紋對象
5.如果request對象中的dont_filter參數設置爲False,並且該request對象的指紋不在信息指紋的隊列中,那麼就把該request對象放到優先級的隊列中
6.從優先級隊列中獲取request對象,交給engine
7.engine將request對象交給下載器下載,期間會通過downloadmiddleware的process_request()方法
8.下載器完成下載,獲得response對象,將該對象交給engine,期間會通過downloadmiddleware的process_response()方法
9.engine將獲得的response對象交給spider進行解析,期間會經過spidermiddleware的process_spider_input()方法
10.從第一步開始循環

上面的十個步驟就是scrapy-redis的整體框架,與scrapy相差無幾。本質的區別就是,將scrapy的內置的去重的隊列和待抓取的request隊列換成了redis的集合。就這一個小小的改動,就使得了scrapy-redis支持了分佈式抓取。

在redis的服務器中,會至少存在三個隊列:
a.用於請求對象去重的集合,隊列的名稱爲spider.name:dupefilter,其中spider.name就是我們自定義的spider的名字,下同。
b.待抓取的request對象的有序集合,隊列的名稱爲spider.name:requests
c.保存提取到item的列表,隊列的名稱爲spider.name:items
d.可能存在存放初始url的集合或者是列表,隊列的名稱可能是spider.name:start_urls

如下圖所示
這裏寫圖片描述
我自定義了一個spider,name屬性爲myspider。當開始運行這個spider的時候,就可以看到在redis的服務器中出現了三個隊列的名字,分別用來去重request對象,存儲提取到的item,存放待抓取的request對象。

那至於spider.name:start_urls這個隊列,裏面存放的是我們第一次啓動爬蟲存放的url,注意是url,而不是scrapy.http.Request對象。如果我們只向這個隊列中存放一條初始的url,那麼這個隊列只會短暫的存在。因爲redis中,如果一個key中沒有數據了,那麼這個key也就消失了。

當然,如果你本身就很瞭解redis的話,這對於你來說,根本就沒有任何難度。

3.編寫scrapy_redis爬蟲

在編寫基於scrapy-redis的爬蟲的時候,我們既可以繼承自scrapy.spiders.Spider這個類,又或者是scrapy.spiders.CrawlSpider,也可以繼承自scrapy-redis的類,比如scrapy_redis.spiders.RedisSpider。

子類化scrapy自身的類時,還是按照scrapy給出的列子一樣,非常的簡單:

from scrapy.spiders import Spider

class MySpider(Spider):
    name = 'myspider'
    allowed_domains = ['www.example.com']
    start_urls = ['http://www.example.com']

    def parse(self, response):
        #do_something_with_response

這裏有一點需要明確一點,當我們沒有爲request對象顯示的指定一個回調函數時,會使用默認的parse()作爲回調函數。

運行上面的代碼,我們就可以在redis服務器看到前面所說的隊列了。

如果我們是子類化scrapy-redis的spider時,情況有些許的不同:

from scrapy_redis,spiders import RedisSpider

class MySpider(RedisSpider):
    name = 'myspider'
    redis_key = 'myspider:start_urls'
    allowed_domains = ['www.example.com']

    def parse(self, response):
        #do_something_with_response     

這裏我們並沒有指定初始url,所以這就需要我們手動的往redis的初始url隊列中添加url,隊列的名稱爲myspider:start_urls.默認情況下我們採用集合的命令進行添加,要不然會報錯的。

sadd myspider:start_urls http://www.example.com

通過往這個隊列中添加初始url,爬蟲就會開始運行了。直到沒有任何request對象,或者待抓取的url。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章