scrapy框架是不可以自己实现分布式的,原因有二。
一:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。(多台机器无法共享同一个调度器)
二:多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。(多台机器无法共享同一个管道)
- 分布式爬虫实现流程
1.环境安装:
pip install scrapy-redis
2.创建工程
scrapy startproject 项目名称
3.创建爬虫文件:RedisCrawlSpider 或者 RedisSpider
scrapy genspider -t crawl xxx www.xxx.com
4.对爬虫文件中的相关属性进行修改:
- 导包:
from scrapy_redis.spiders import RedisCrawlSpider
- 将当前爬虫文件的父类设置成RedisCrawlSpider
class ChoutiSpider(RedisCrawlSpider): pass
- 将起始url列表替换成redis_key = 'xxx'(调度器队列的名称)
class ChoutiSpider(RedisCrawlSpider): #name用不到,但是不能注释,否则会报错 name = 'chouti' # allowed_domains = ['www.xxx.com'] # 注释start_urls # start_urls = ['http://www.xxx.com/'] # 设置redis_key redis_key = 'chouti'#调度器队列的名称
5.在配置文件中进行配置:
- 使用组件中封装好的可以被共享的管道类:
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’}
- 配置redis数据库的配置文件,找到redis的配置文件
- 取消保护模式:protected-mode no - bind绑定: #bind 127.0.0.1 注释此行
- 启动redis
开启redis服务器:redis-server 配置文件
开启redis客户端:redis-cli
6.执行分布式程序
scrapy runspider xxx.py(爬虫文件)
7.向调度器队列中仍入一个起始url:
在redis-cli中执行:
lpush redis_key属性值 起始url
代码示例 : redis分布式爬取抽屉
爬虫文件 :

1 # -*- coding: utf-8 -*- 2 import scrapy 3 from scrapy.linkextractors import LinkExtractor 4 from scrapy.spiders import CrawlSpider, Rule 5 from scrapy_redis.spiders import RedisCrawlSpider 6 from redisChoutiPro.items import RedischoutiproItem 7 class ChoutiSpider(RedisCrawlSpider): 8 name = 'chouti' 9 # allowed_domains = ['www.xxx.com'] 10 # start_urls = ['http://www.xxx.com/'] 11 redis_key = 'chouti'#调度器队列的名称 12 rules = ( 13 Rule(LinkExtractor(allow=r'/all/hot/recent/\d+'), callback='parse_item', follow=True), 14 ) 15 16 def parse_item(self, response): 17 div_list = response.xpath('//div[@class="item"]') 18 for div in div_list: 19 title = div.xpath('./div[4]/div[1]/a/text()').extract_first() 20 author = div.xpath('./div[4]/div[2]/a[4]/b/text()').extract_first() 21 item = RedischoutiproItem() 22 item['title'] = title 23 item['author'] = author 24 25 yield item
items.py :

1 # -*- coding: utf-8 -*- 2 3 # Define here the models for your scraped items 4 # 5 # See documentation in: 6 # https://doc.scrapy.org/en/latest/topics/items.html 7 8 import scrapy 9 10 11 class RedischoutiproItem(scrapy.Item): 12 # define the fields for your item here like: 13 title = scrapy.Field() 14 author = scrapy.Field()
settings.py :

1 ITEM_PIPELINES = { 2 'scrapy_redis.pipelines.RedisPipeline': 400 3 } 4 5 # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化 6 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" 7 # 使用scrapy-redis组件自己的调度器 8 SCHEDULER = "scrapy_redis.scheduler.Scheduler" 9 # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 10 SCHEDULER_PERSIST = True #数据指纹 11 12 REDIS_HOST = '127.0.0.1' 13 REDIS_PORT = 6379