Scrapy
Scrapy是一個比較好用的Python爬蟲框架,你只需要編寫幾個組件就可以實現(xiàn)網(wǎng)頁數(shù)據(jù)的爬取。但是當我們要爬取的頁面非常多的時候,單個主機的處理能力就不能滿足我們的需求了(無論是處理速度還是網(wǎng)絡(luò)請求的并發(fā)數(shù)),這時候分布式爬蟲的優(yōu)勢就顯現(xiàn)出來。
而Scrapy-Redis則是一個基于Redis的Scrapy分布式組件。它利用Redis對用于爬取的請求(Requests)進行存儲和調(diào)度(Schedule),并對爬取產(chǎn)生的項目(items)存儲以供后續(xù)處理使用。scrapy-redi重寫了scrapy一些比較關(guān)鍵的代碼,將scrapy變成一個可以在多個主機上同時運行的分布式爬蟲。
原生的Scrapy的架構(gòu)是這樣子的:
加上了Scrapy-Redis之后的架構(gòu)變成了:
scrapy-redis的官方文檔寫的比較簡潔,沒有提及其運行原理,所以如果想全面的理解分布式爬蟲的運行原理,還是得看scrapy-redis的源代碼才行,不過scrapy-redis的源代碼很少,也比較好懂,很快就能看完。
scrapy-redis工程的主體還是是redis和scrapy兩個庫,工程本身實現(xiàn)的東西不是很多,這個工程就像膠水一樣,把這兩個插件粘結(jié)了起來。
scrapy-redis提供了哪些組件?
scrapy-redis所實現(xiàn)的兩種分布式:爬蟲分布式以及item處理分布式。分別是由模塊scheduler和模塊pipelines實現(xiàn)。
connection.py
負責根據(jù)setting中配置實例化redis連接。被dupefilter和scheduler調(diào)用,總之涉及到redis存取的都要使用到這個模塊。
import redisimport sixfrom scrapy.utils.misc import load_objectDEFAULT_REDIS_CLS = redis.StrictRedis# Sane connection defaults.DEFAULT_PARAMS = { 'socket_timeout': 30, 'socket_connect_timeout': 30, 'retry_on_timeout': True,}# Shortcut maps 'setting name' -> 'parmater name'.SETTINGS_PARAMS_MAP = { 'REDIS_URL': 'url', 'REDIS_HOST': 'host', 'REDIS_PORT': 'port',}def get_redis_from_settings(settings): """Returns a redis client instance from given Scrapy settings object. This function uses ``get_client`` to instantiate the client and uses ``DEFAULT_PARAMS`` global as defaults values for the parameters. You can override them using the ``REDIS_PARAMS`` setting. Parameters ---------- settings : Settings A scrapy settings object. See the supported settings below. Returns ------- server Redis client instance. Other Parameters ---------------- REDIS_URL : str, optional Server connection URL. REDIS_HOST : str, optional Server host. REDIS_PORT : str, optional Server port. REDIS_PARAMS : dict, optional Additional client parameters. """ params = DEFAULT_PARAMS.copy() params.update(settings.getdict('REDIS_PARAMS')) # XXX: Deprecate REDIS_* settings. for source, dest in SETTINGS_PARAMS_MAP.items(): val = settings.get(source) if val: params[dest] = val # Allow ``redis_cls`` to be a path to a class. if isinstance(params.get('redis_cls'), six.string_types): params['redis_cls'] = load_object(params['redis_cls']) return get_redis(**params)# Backwards compatible alias.from_settings = get_redis_from_settingsdef get_redis(**kwargs): """Returns a redis client instance. Parameters ---------- redis_cls : class, optional Defaults to ``redis.StrictRedis``. url : str, optional If given, ``redis_cls.from_url`` is used to instantiate the class. **kwargs Extra parameters to be passed to the ``redis_cls`` class. Returns ------- server Redis client instance. """ redis_cls = kwargs.pop('redis_cls', DEFAULT_REDIS_CLS) url = kwargs.pop('url', None) if url: return redis_cls.from_url(url, **kwargs) else: return redis_cls(**kwargs)
新聞熱點
疑難解答
圖片精選