redis分布式部署
1. 概念: 使用多台机器组成一个分布式的机群,在机群中运行同一组程序,进行联合数据的爬取。
2. scrapy框架是否可以自己实现分布式?
- 不可以
- 原因:
1) 因为多台机器上部署的scrapy会各自拥有自己的调度器, 这样多台机器无法分配start_urls列表中的url (多台机器无法共享同一个调度器)
2) 多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久存储 (多台机器无法共享同一个管道)
3. 基于scrapy-redis模块的分布式爬虫
- scrapy-redis组件中为我们封装好了可以被多台机器共享的调度器和管道,可以直接使用并实现分布式数据爬取。
- 实现方式:
- 基于该组件的RedisSpider类
- 基于该组件的RedisCrawlSpider类
4. 分布式爬虫流程
1) pip install scrapy-redis
2) 创建工程: scrapy startproject Name
3) 创建爬虫文件: scrapy genspider -t crawl Name www.xxx.com
4) 修改爬虫文件
- 导包: from scrapy_redis.spiders import RedisCrawlSpider
- 将爬虫类继承的父类修改RedisCrawlSpider (如果爬虫文件是基于Spider,将父类修改成RedisSpider)
- 注释或删除 allowed_domains,start_url
- 添加一个新属性redis_key (scrpy-redis组件中调度器队列的名称)
- 数据解析, 将解析的数据封装到item中然后向管道提交
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的配置文件进行配置
- # bind 127.0.0.1 # 其他ip可以访问redis
- protected-mode no # 其他ip可以操作redis
- 开启redis
- redis-server redis.windows.conf # 指定配置文件
- redis-cli # 开启客户端
- 运行爬虫文件: scrapy runspider SpiderFile # 监听状态
- 向调度器队列中扔入一个起始url(在redis客户端中操作): lpush redis_key属性值 起始url
示例
# 爬虫文件
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from FBSPro.items import FbsproItem
class TestSpider(RedisCrawlSpider):
name = 'test'
# allowed_domains = ['www.xxx.com']
# start_urls = ['http://www.xxx.com/']
redis_key = 'dongguan'
link = LinkExtractor(allow=r'type=4&page=\d+')
rules = (
Rule(link, callback='parse_item', follow=True),
)
def parse_item(self, response):
a_list = response.xpath('//a[@class="news14"]')
for a in a_list:
item = FbsproItem()
item['title'] = a.xpath('./text()').extract_first()
yield item
# items文件
class FbsproItem(scrapy.Item):
title = scrapy.Field()
# settings文件配置
# 指定基于scrapy-redis的管道
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400
}
# 调度器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_PERSIST = True
# 连接redis
REDIS_HOST = '192.168.11.166'
REDIS_PORT = 6379