引子 : scrapy框架可否本身實現分佈式 ? redis
- 不能夠 windows
- 緣由一 : 由於多臺機器上部署的scrapy會各自擁有各自的調度器,這樣就使得多態機器沒法分配 start_urls 列表中的url . (多臺機器沒法共享同一個調度器)服務器
- 緣由二 : 多臺機器爬取到的數據沒法經過一個管道對數據進行統一的數據持久化存儲(多臺機器沒法共享同一個管道),就會形成數據的大量重複.框架
1 . 組件實現 dom
- 在scrapy框架中作分佈式爬蟲是基於scrapy-redis組件進行的scrapy
- 實現方法 : 分佈式
- 基於該組件的RedisSpider類ide
- 基於該組件的RedisCrawlSpiderurl
2 . 分佈式實現的流程 : spa
2.1 下載scrapy-redis組件 : pip install scrapy-redis
2.2 redis 配置文件的修改 :
56行 - 註釋該行:bind 127.0.0.1,表示可讓其餘ip訪問redis 76行 - 將yes該爲no:protected-mode no,表示可讓其餘ip操做redis # redis-windows-conf 文件
2.3 建立工程 : scrapy startproject xxx(項目名)
建立爬蟲文件 : 繼承與 --> RedisCrawlSpider / RedisSpider
scrapy genspider -t crawl xxx www.xxx.com (咱們使用的是RedisCrawlSpider )
2.4 對爬蟲文件中的屬性進行修改 :
#- 導包: from scrapy_redis.spiders import RedisCrawlSpider #- 將當前爬蟲文件的父類設置成 RedisCrawlSpider #- 將起始url列表替換成 redis_key = 'xxx'(調度器隊列的名稱)
爬蟲文件 fenbu_hh.py :
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapy_redis.spiders import RedisCrawlSpider from fenbu.items import FenbuItem class FenbuHhSpider(RedisCrawlSpider): name = 'fenbu_hh' # allowed_domains = ['www.xxx.com'] # start_urls = ['http://www.xxx.com/'] """ 分佈式爬蟲,代碼編寫好後能夠放到分佈式集羣中,集羣中運行的程序時同一個,若是程序中有起始 的url,就表示全部的機器都url,要去請求這個url進行解析-->會致使更多的重複數據 作分佈式就是要其中的某臺電腦有url,從url中解析出子url,扔到調度器的隊列中 由於在調度器中,通過去重的url纔會放到隊列中. 可是起始url還不能沒有,就把起始url當成全局的,讓集羣中的機器其搶,誰搶到誰請求解析 保證起始url只被請求一次 https://dig.chouti.com/ """ # 能夠被共享的調度器的名稱, # 當程序執行以後,手動向調度器的對類中放一個起始url
redis_key = 'chouti' # 調度器隊列的名稱 ********** rules = ( Rule(LinkExtractor(allow=r'/all/hot/recent/\d+'), callback='parse_item', follow=True), ) def parse_item(self, response): div_list = response.xpath('//div[@class="item"]') for div in div_list: title = div.xpath('./div[4]/div[1]/a/text()').extract_first() author = div.xpath('/div[4]/div[2]/a[4]/b/text()').extract_first() # 實例化item對象進行封裝 item = FenbuItem() item['title'] = title item['author'] = author yield item
2.5 在配置文件中進行配置
注意 : UA , ROBOTSTXT_OBEY = False 不要忘記也要修改
#- 使用組件中封裝好的能夠被共享的管道類: ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } #- 配置調度器(使用組件中封裝好的能夠被共享的調度器) # 增長了一個去重容器類的配置, 做用使用Redis的set集合來存儲請求的指紋數據, 從而實現請求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis組件本身的調度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置調度器是否要持久化, 也就是當爬蟲結束了, 要不要清空Redis中請求隊列和去重指紋的set。若是是True, 就表示要持久化存儲, 就不清空數據, 不然清空數據 SCHEDULER_PERSIST = True #- 指定存儲數據的redis: REDIS_HOST = 'redis服務的ip地址' REDIS_PORT = 6379 REDIS_ENCODING = ‘utf-8’ REDIS_PARAMS = {‘password’:’123456’}
3 . 開啓redis服務器 : redis-server
開始redis客戶端 : redis-cli
4 . 運行爬蟲文件 : scrapy runspider fenbu_hh.py
注意 : 要cd 到 spiders 裏面在執行
在執行以後,會夯住
5 . 向調度器隊列中扔一個起始url (在redis的客戶端操做) :
lpush chouti https://dig.chouti.com/ (lpush redis_key屬性值 起始url)
這個時候,爬蟲文件就會繼續執行
6 . scrapy-redis 的調度器如何實現任務的深度優先和廣度優先
在scrapy-redis中,默認的是 深度優先
若是想變成 廣度優先,在配置文件中寫入
- DEPTH_PRIORITY = 1\n, - SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'\n, - SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'\n,
深度優先和廣度優先的對比
- 廣度優先:不所有保留結點,佔用空間少;運行速度慢\n,
- 深度優先:保留所有結點,佔用空間大;運行速度快