引子 : 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,
- 深度优先:保留所有结点,占用空间大;运行速度快