一、分布式爬虫 scrapy-redis
Scrapy-redis为了实现Scrapy分布式提供了一些以redis为基础的组件
https://github.com/rmax/scrapy-redis/
有能人改变了scrapy的队列调度,将起始的网址从start_urls里分离出来,改为从redis读取,多个客户端可以同时读取同一个redis,从而实现了分布式的爬虫 (比如:打印机,每个用户都可以使用)
需要安装:pip install scrapy_redis 安装命令中间是下划线_, 下载好以后显示是横线-
scrapy-redis架构
Scheduler(调度器):
- Scrapy的Scrapy queue 换成 redis 数据库, 多个 spider 从同一个 redis-server 获取要爬取request
- Scheduler 对新的request进行入队列操作, 取出下个要爬取的request给爬虫, 使用Scrapy-redis的scheduler组件
Duplication Filter(指纹去重):
- 在scrapy-redis中去重是由Duplication Filter组件来实现的, 通过redis的set不重复的特性
- scrapy-redis调度器从引擎接受request, 并指纹存⼊set检查是否重复, 不重复写⼊redis的request queue
Item Pipeline(管道):
- 引擎将爬取到的Item给Item Pipeline, scrapy-redis组件的Item Pipeline将爬取到的Item存⼊redis的items队列里
Base Spider(爬虫):
- RedisSpider继承了Spider和RedisMixin这两个类, RedisMixin用来从redis读取url的类
- 我们写个Spider类继承RedisSpider, 调用setup_redis函数去连接redis数据库, 然后设置signals(信号)
- 当spider空闲时候的signal, 会调用spider_idle函数, 保证spider是一直活着的状态
- 当有item时的signal, 会调用item_scraped函数, 获取下一个request
二、scrapy-Redis分布式策略:
Slaver端从Master端拿任务(Request/url/ID)进行数据抓取,在抓取数据的同时也生成新任务,并将任务抛给Master。Master端只有一个Redis数据库,负责对Slaver提交的任务进行去重、加入待爬队列。
优点:scrapy-redis默认使用的就是这种策略,我们实现起来很简单,因为任务调度等工作scrapy-redis都已经帮我们做好了,我们只需要继承RedisSpider、指定redis_key就行了。
缺点:scrapy-redis调度的任务是Request对象,里面信息量比较大(不仅包含url,还有callback函数、headers等信息),导致的结果就是会降低爬虫速度、而且会占用Redis大量的存储空间。当然我们可以重写方法实现调度url。
三、将之前某个网修改为基于RedisSpider类的scrapy-redis分布式爬虫项目,将数据存入redis数据库。
(1)item文件不需要修改
(2) spiders爬虫文件,使用RedisSpider类替换之前的Spider类,其余地方做些许改动即可,具体代码如下:
#(1)导包
from scrapy_redis.spiders import RedisSpider
#(2)修改RedisSpider
class SixSpider(RedisSpider):
name = 'six'
#(3) redis的键值对名称
redis_key = 'hsx'
(3) 修改settings文件设置
#过滤操作,资源路径:类
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#调度器的指定,资源路径
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#调度器的持久化,断点续爬
SCHEDULER_PERSIST = True
#redis管道代替了原来的管道
ITEM_PIPELINES = {
# 'example.pipelines.ExamplePipeline': 300, #本地管道
'scrapy_redis.pipelines.RedisPipeline': 400,
}
#log等级
LOG_LEVEL = 'DEBUG'
#下载延迟
DOWNLOAD_DELAY = 3
(4) 启动爬虫程序 (注意:在运行之前启动redis服务器)
scrapy crawl six
执行程序后终端窗口显示如下:
原因:因为没有起始url,需要去redis数据库中创建起始url
解决: 在Master端的redis-cli输入push指令,参考格式:
打开redis-cli客户端,输入以下命令
127.0.0.1:6379> lpush hsx https://www.sixstaredu.com/teacher
说明:
hsx: 是爬虫文件中redis_key = 'hsx' 中的值
https://www.sixstaredu.com/teacher: 就是起始网址start_url
通过观察:
redis在scrapy-redis中起到的作用:
1.可以代替调度器,保存request请求对象,分配给各个服务器 -- "six:requests"
2.可以代替item,pipelines里面的item保存数据 -- "six:items"
3.任务的去重,断点续爬(哪里暂停就从哪里开始) -- "six:dupefilter"
(5)获取数据
所有Slaver端将开始爬取数据,数据将保存在Redis数据库中,并共享Redis数据库的请求队列、请求指纹集合和数据队列。