Scrapy-Redis代碼實戰html
Scrapy 是一個通用的爬蟲框架,可是不支持分佈式,Scrapy-redis是爲了更方便地實現Scrapy分佈式爬取,而提供了一些以redis爲基礎的組件(僅有組件)。node
scrapy-redis在scrapy的架構上增長了redis,基於redis的特性拓展了以下四種組件:python
Base Spiderredis
Scrapy本來的queue是不支持多個spider共享一個隊列的,scrapy-redis經過將queue改成redis實現隊列共享。數據庫
Scrapy中經過Python中的集合實現request指紋去重,在scrapy-redis中去重是由Duplication Filter組件來實現的,它經過redis的set不重複的特性,巧妙的實現了DuplicationFilter去重。segmentfault
引擎將(Spider返回的)爬取到的Item給Item Pipeline,scrapy-redis 的Item Pipeline將爬取到的 Item 存入redis的 items queue。修改過Item Pipeline能夠很方便的根據 key 從 items queue提取item,從而實現 items processes集羣。架構
再也不使用scrapy原有的Spider類,重寫的RedisSpider繼承了Spider和RedisMixin這兩個類,RedisMixin是用來從redis讀取url的類。
當咱們生成一個Spider繼承RedisSpider時,調用setup_redis函數,這個函數會去鏈接redis數據庫,而後會設置signals(信號):一個是當spider空閒時候的signal,會調用spider_idle函數,這個函數調用schedule_next_request函數,保證spider是一直活着的狀態,而且拋出DontCloseSpider異常。一個是當抓到一個item時的signal,會調用item_scraped函數,這個函數會調用schedule_next_request函數,獲取下一個request框架
python3.6 -m pip install scrapy-redis
首先修改配置文件scrapy
BOT_NAME = 'cnblogs' SPIDER_MODULES = ['cnblogs.spiders'] NEWSPIDER_MODULE = 'cnblogs.spiders' # Obey robots.txt rules ROBOTSTXT_OBEY = False # Configure maximum concurrent requests performed by Scrapy (default: 16) #CONCURRENT_REQUESTS = 32 # See also autothrottle settings and docs #DOWNLOAD_DELAY = 3 DOWNLOAD_DELAY = 2 # 等待2s MY_USER_AGENT = ["Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36", "Mozilla/5.0+(Windows+NT+5.1)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/28.0.1500.95+Safari/537.36+SE+2.X+MetaSr+1.0", "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/50.0.2657.3+Safari/537.36"] # Enable or disable downloader middlewares # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html DOWNLOADER_MIDDLEWARES = { 'cnblogs.middlewares.UserAgentMiddleware': 543, } LOG_LEVEL = "ERROR" ITEM_PIPELINES = { 'cnblogs.pipelines.MongoPipeline': 300, } #將結果保存到Mongo數據庫 MONGO_HOST = "127.0.0.1" # 主機IP MONGO_PORT = 27017 # 端口號 MONGO_DB = "spider_data" # 庫名 MONGO_COLL = "cnblogs_title" # collection名 #須要將調度器的類和去重的類替換爲 Scrapy-Redis 提供的類 SCHEDULER = "scrapy_redis.scheduler.Scheduler" DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" REDIS_HOST = '127.0.0.1' REDIS_PORT = 7001 #Redis集羣中其中一個節點的端口 #配置持久化 #Scrapy-Redis 默認會在爬取所有完成後清空爬取隊列和去重指紋集合。 #SCHEDULER_PERSIST = True #設置重爬 #SCHEDULER_FLUSH_ON_START = True
代碼要改的地方有兩處:
第一處是繼承的RedisSpider
第二處就是start_urls改成了redis_key。分佈式
# -*- coding: utf-8 -*- import scrapy import datetime from scrapy_redis.spiders import RedisSpider class CnblogSpider(RedisSpider): name = 'cnblog' redis_key = "myspider:start_urls" #start_urls = [f'https://www.cnblogs.com/c-x-a/default.html?page={i}' for i in range(1,2)] def parse(self, response): main_info_list_node = response.xpath('//div[@class="forFlow"]') content_list_node = main_info_list_node.xpath(".//a[@class='postTitle2']/text()").extract() for item in content_list_node: url = response.url title=item crawl_date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') item = {} item['url'] = url item['title'] = title.strip() if title else title item['crawl_date'] = crawl_date yield item
由於Scrapy-Redis是以Redis爲隊列進行消息共享的,因此咱們的任務須要提早插入到數據庫,它的key就叫咱們指定的"myspider:start_urls"。
在以前建立好的redis集羣中插入任務,首先使用集羣的模式鏈接數據庫
redis-cli -c -p 7000 #個人redis集羣的一個Master節點端口
執行下面的語句插入任務
lpush myspider:start_urls https://www.cnblogs.com/c-x-a/default.html?page=1 lpush myspider:start_urls https://www.cnblogs.com/c-x-a/default.html?page=2
而後查看
lrange myspider:start_urls 0 10
看到咱們的任務,好了任務插入成功了。
接下來就是運行代碼了,運行完代碼以後,去查看三處。
第一處,查看redis的任務發現任務已經沒有了
(empty list or set)
第二處,查看mongo數據庫,發現咱們成功保存告終果。
第三處,你會發現的你爬蟲程序並無結束,這個實際上是正常的,由於咱們使用了scrapy-redis以後,爬蟲程序會一直取redis中的任務,若是沒有任務了就等待,若是在redis插入了新的任務他就會繼續進行爬蟲程序,以後又進入等待任務的狀態。
關注公衆號:Python學習開發,後臺回覆:redis便可獲取源碼。
https://segmentfault.com/a/1190000014333162?utm_source=channel-hottest