scrapy-redis分布式爬蟲的搭建過程(理論篇)
1. 背景 Scrapy 是一個通用的爬蟲架構,但是不支援分布式,Scrapy-redis是為了更方便地實現Scrapy分布式爬取,而提供了一些以redis為基礎的組件(僅有組件)。
2. 環境 系統:win7 scrapy-redis redis 3.0.5 python 3.6.1
3. 原理
3.1. 對比一下scrapy 和 Scrapy-redis 的架構圖。
scrapy架構圖:
scrapy-redis 架構圖:
多了一個redis組件,主要影響兩個地方:第一個是調度器。第二個是資料的處理。 3.2. Scrapy-Redis分布式策略。
作為一個分布式爬蟲,是需要有一個Master端(核心伺服器)的,在Master端,會搭建一個Redis資料庫,用來儲存start_urls、request、items。Master的職責是負責url指紋判重,Request的分配,以及資料的儲存(一般在Master端會安裝一個mongodb用來儲存redis中的items)。出了Master之外,還有一個角色就是slaver(爬蟲程式執行端),它主要負責執行爬蟲程式爬取資料,並將爬取過程中新的Request提交到Master的redis資料庫中。 如上圖,假設我們有四台電腦:A, B, C, D ,其中任意一台電腦都可以作為 Master端 或 Slaver端。整個流程是:
首先Slaver端從Master端拿任務(Request、url)進行資料抓取,Slaver抓取資料的同時,產生新任務的Request便提交給 Master 處理; Master端只有一個Redis資料庫,負責將未處理的Request去重和任務分配,將處理後的Request加入待爬隊列,並且儲存爬取的資料。
Scrapy-Redis預設使用的就是這種策略,我們實現起來很簡單,因為任務調度等工作Scrapy-Redis都已經幫我們做好了,我們只需要繼承RedisSpider、指定redis_key就行了。
缺點是,Scrapy-Redis調度的任務是Request對象,裡面資訊量比較大(不僅包含url,還有callback函數、headers等資訊),可能導致的結果就是會降低爬蟲速度、而且會佔用Redis大量的儲存空間,所以如果要保證效率,那麼就需要一定硬體水平。 4. 運行流程 第一步:在slaver端的爬蟲中,指定好 redis_key,並指定好redis資料庫的地址,比如:
class MySpider(RedisSpider): """Spider that reads urls from redis queue (myspider:start_urls).""" name = 'amazon' redis_key = 'amazonCategory:start_urls'
# 指定redis資料庫的串連參數'REDIS_HOST': '172.16.1.99','REDIS_PORT': 6379,
第二步:啟動slaver端的爬蟲,爬蟲進入等待狀態,
等待 redis 中出現 redis_key ,Log如下:
2017-12-12 15:54:18 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapybot)2017-12-12 15:54:18 [scrapy.utils.log] INFO: Overridden settings: {'SPIDER_LOADER_WARN_ONLY': True}2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled extensions:['scrapy.extensions.corestats.CoreStats', 'scrapy.extensions.telnet.TelnetConsole', 'scrapy.extensions.logstats.LogStats']2017-12-12 15:54:18 [myspider_redis] INFO: Reading start URLs from redis key 'myspider:start_urls' (batch size: 110, encoding: utf-82017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled downloader middlewares:['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware', 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware', 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware', 'redisClawerSlaver.middlewares.ProxiesMiddleware', 'redisClawerSlaver.middlewares.HeadersMiddleware', 'scrapy.downloadermiddlewares.retry.RetryMiddleware', 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware', 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware', 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware', 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware', 'scrapy.downloadermiddlewares.stats.DownloaderStats']2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled spider middlewares:['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware', 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware', 'scrapy.spidermiddlewares.referer.RefererMiddleware', 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware', 'scrapy.spidermiddlewares.depth.DepthMiddleware']2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled item pipelines:['redisClawerSlaver.pipelines.ExamplePipeline', 'scrapy_redis.pipelines.RedisPipeline']2017-12-12 15:54:18 [scrapy.core.engine] INFO: Spider opened2017-12-12 15:54:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)2017-12-12 15:55:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)2017-12-12 15:56:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
第三步:啟動指令碼,往redis資料庫中填入
redis_key(start_urls)
#!/usr/bin/env python# -*- coding:utf-8 -*-import redis# 將start_url 儲存到redis中的redis_key中,讓爬蟲去爬取redis_Host = "172.16.1.99"redis_key = 'amazonCategory:start_urls'# 建立redis資料庫連接rediscli = redis.Redis(host = redis_Host, port = 6379, db = "0")# 先將redis中的requests全部清空flushdbRes = rediscli.flushdb()print(f"flushdbRes = {flushdbRes}")rediscli.lpush(redis_key, "https://www.baidu.com")
第四步:slaver端的爬蟲開始爬取資料。Log如下:
2017-12-12 15:56:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)parse url = https://www.baidu.com, status = 200, meta = {'download_timeout': 25.0, 'proxy': 'http://proxy.abuyun.com:9020', 'download_slot': 'www.baidu.com', 'download_latency': 0.2569999694824219, 'depth': 7}parse url = https://www.baidu.com, status = 200, meta = {'download_timeout': 25.0, 'proxy': 'http://proxy.abuyun.com:9020', 'download_slot': 'www.baidu.com', 'download_latency': 0.8840000629425049, 'depth': 8}2017-12-12 15:57:18 [scrapy.extensions.logstats] INFO: Crawled 2 pages (at 2 pages/min), scraped 1 items (at 1 items/min)
第五步:啟動指令碼,將redis中的items,轉儲到mongodb中。
這部分代碼,請參照:scrapy-redis分布式爬蟲的搭建過程(代碼篇)
5. 環境安裝以及代碼編寫
5.1. scrapy-redis環境安裝
pip install scrapy-redis
代碼位置:後面可以進行修改定製。
5.2. scrapy-redis分布式爬蟲編寫 第一步,下載官網的範例程式碼,地址:https://github.com/rmax/scrapy-redis (需要安裝過git)
git clone https://github.com/rmax/scrapy-redis.git
官網提供了兩種範例程式碼,分別繼承自 Spider + redis 和 CrawlSpider + redis
第二步,根據官網提供的範例程式碼進行修改。