背景:
眾所周知,Redis預設的配置會產生db0~db15共16個db,切分出16個db的一個作用是方便不同項目使用不同的db,防止的資料混淆,也為了方便資料查看。
Python在串連Redis時如果沒有指定用哪一個db則預設使用db0。使用過scrapy_redis模組的同學也知道去重和種子隊列都在db0上。
現在有一個基於scrapy、Redis的分布式爬蟲,是從同事那邊接手過來的。原先沒覺得scrapy_redis使用db2來存放request和dupefilter有什麼難度,也就沒在意他的代碼是怎麼實現的了,只知道他的爬蟲將種子和去重都放在了db2。昨天添加功能改代碼,將代碼從伺服器拷貝出來跑測試,探索資料是存放在db0中的。仔細看了代碼,沒發現哪裡改成了db2,但伺服器上跑為什麼會把資料存到db2呢。一樣的代碼,儲存的地方竟然不一樣。大惑。
半信半疑地去看了一下伺服器中scrapy_redis的源碼,發現connection.py中連Redis的代碼竟然被改了。
也是有點醉。直接改python模組的原始碼是大忌。雖然這樣改簡單快捷,但是模組是公用的代碼,如果其他項目也要用到這個項目的話就亂了,而且也不利於本項目代碼的遷移,與飲鴆止渴無差。
然後看了scrapy_redis模組的源碼,發現scrapy_redis在串連Redis時並沒有指定db,預設db0。並沒有介面讓使用者指定db。那麼問題來了,scrapy_redis想要使用redis的db2,該怎麼做。
解決:
1、同事那個改法就很簡單快捷(如上方圖片),但是不能直接改模組源碼,要把源碼複製一份出來,放在項目目錄下,然後進行修改。項目調用scrapy_redis時也是調用本目錄下的scrapy_redis。
2、第二種是用繼承。見上方的圖片,代碼的作用是執行個體化產生一個redis連線物件,一般情況下是返回redis.Redis()對象。這個方法被scheduler.py下的from_settings()方法調用。代碼如下:
我們可以繼承這個方法,再來個偷梁換柱。
具體方法:在settings.py同級目錄下建立一個檔案schedulerOverwrite.py,填入下面的代碼。然後在settings.py設定SCHEDULER=schedulerOverwrite.SchedulerSon,之後在settings.py中設定REDIS_DB=XXX即可指定db。
import redisfrom scrapy_redis.scheduler import Schedulerfrom scrapy.utils.misc import load_object# default valuesSCHEDULER_PERSIST = FalseQUEUE_KEY = '%(spider)s:requests'QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'DUPEFILTER_KEY = '%(spider)s:dupefilter'IDLE_BEFORE_CLOSE = 0REDIS_URL = NoneREDIS_HOST = 'localhost'REDIS_PORT = 6379REDIS_DB = 0def from_settings(settings): url = settings.get('REDIS_URL', REDIS_URL) host = settings.get('REDIS_HOST', REDIS_HOST) port = settings.get('REDIS_PORT', REDIS_PORT) db = settings.get('REDIS_DB', REDIS_DB) # REDIS_URL takes precedence over host/port specification. if url: return redis.from_url(url) else: return redis.Redis(host=host, port=port, db=db)class SchedulerSon(Scheduler): @classmethod def from_settings(cls, settings): persist = settings.get('SCHEDULER_PERSIST', SCHEDULER_PERSIST) queue_key = settings.get('SCHEDULER_QUEUE_KEY', QUEUE_KEY) queue_cls = load_object(settings.get('SCHEDULER_QUEUE_CLASS', QUEUE_CLASS)) dupefilter_key = settings.get('DUPEFILTER_KEY', DUPEFILTER_KEY) idle_before_close = settings.get('SCHEDULER_IDLE_BEFORE_CLOSE', IDLE_BEFORE_CLOSE) server = from_settings(settings) return cls(server, persist, queue_key, queue_cls, dupefilter_key, idle_before_close)
轉載請註明出處,謝謝。(原文連結:http://blog.csdn.net/bone_ace/article/details/54139500)