1. 分布式爬虫简介
1.1. 分布式系统介绍
- 分布式概念
-- 分布式系统是由一组多台计算机组成的系统;
-- 计算机之间通过网络进行通信;
-- 计算机之间为完成共同的任务而协调工作;
-- 分布式系统的目的是为了利用更多的机器,处理更多的数据,完成更多的任务; - 分布式系统的实现
-- 分布式系统的实现包括 MapReduce 和 Replication;
-- MapReduce:分布式系统实现的核心思想,是分片(partition),每个节点(node)处理一部分任务,最后将结果汇总,该思路即 MapReduce;
-- Replication:在实践中,分布式系统会遇到断网、高延迟、单节点故障等情况,需要系统具有高容错能力,常用的解决办法是冗余(replication),即多节点负责同一任务,常见于分布式存储,该思路即 Replication; - 分布式系统需要解决的问题
-- 机器 & 网络 异构;
-- 节点故障监控;
-- 网络丢包、延时、乱序等;
关于分布式系统,详情请参考链接:
《什么是分布式系统,如何学习分布式系统》
https://www.cnblogs.com/xybaby/p/7787034.html
1.2. 分布式爬虫介绍
1.2.1. 分布式爬虫分类
-
主从式爬虫
-- 整个分布式爬虫系统由两部分组成:master控制节点和slave爬虫节点;
-- master控制节点:负责管理所有slave,包括 slave 连接、任务调度、分发,维护爬取队列、 收取 salve 上传的数据,存储目标数据,新 URL 链接去重,新任务添加等、结果回收、汇总;
-- slave爬虫节点负责: 从 master 领取任务,并独自完成、本节点爬虫调度、数据抓取、HTML下载管理、数据处理、内容解析(解析包括目标数据和新的URL链接)、数据存储、上传结果;
注意:
- 主从模式下 slave 节点不需要与其他 slave 节点交流;
- 主从模式下,负载瓶颈在服务器端,主服务器不做爬取;
-- 主从式爬虫架构如下图:
- 对等式爬虫
-- 对等式爬虫模式下,所有节点工作任务相同;
-- 这是为了解决控制节点作为爬虫系统核心带来的瓶颈问题而设计的;
-- 这种模式一般用于超大规模爬虫如搜索引擎,此处不做赘述;
1.2.2. 分布式爬虫的优势
- 解决目标地址对IP访问频率的限制的问题;
- 利用更高的带宽,提高下载速度;
- 大规模系统的分布式存储和备份;
- 系统可扩展性;
1.2.3 分布式爬虫需要解决的问题
- request 队列管理;
- 爬虫的集中去重;
- 爬取数据的统一存储;
关于分布式爬虫,详情请参考:
《简单分布式爬虫——第一弹:了解分布式爬虫结构》https://www.jianshu.com/p/d148ccc3e50a
《网络爬虫 | 你知道分布式爬虫是如何工作的吗?》https://www.jianshu.com/p/6e3eb50fe2b8
2. Scrapy-redis 介绍
2.1. scrapy-redis 简介
- scrapy 相关介绍此处不再赘述,详情参考:http://www.scrapyd.cn/;
- scrapy-redis是一个基于 redis 的 scrapy 插件;
- 使用 Redis 数据库写入、存放和读取 URL 待爬取队列;
- 通过它可以快速实现简单分布式爬虫程序,
- 该组件本质上提供了三大功能:
-- scheduler 调度器;
-- dupefilter URL去重;
-- pipeline 数据持久化; -
scrapy-redis 架构图:
2.2. Redis 数据库在 scrapy_redis 中的作用
- 存请求队列
- 存指纹
-- 当请求到达 Redis 之后,先和之前的请求做指纹比对,如果指纹已存在则丢弃,否则存储请求; - 分布式爬虫中,所有的爬虫 spider 共享 Redis 队列和指纹。
2.3. scrapy_redis 与 scrapy 的区别
- 增加了 Redis 数据库;
- 队列:
-- scrapy 本身不支持爬虫 request 队列共享,即一个队列只能服务于一个爬虫,不支持分布式爬取;
-- scrapy-redis 则把 request 队列存放于 Redis 数据库,多个爬虫 spider 可以到同一个 Redis 数据库里读取; - 去重:
-- scrapy 使用 set 集合实现 request 去重,通过将 request 与 set 中的已有 request 进行比对,如果已存在则丢弃;
-- scrapy-redis 使用 Dupelication Filter 组件实现去重,scrapy-redis 调度器从引擎接受 request 并判断是否重复,并将不重复的 reuquest 写入 Redis 中的 队列,之后调度器从队列中根据优先级 pop 出一个 reuqest 发送给爬虫引擎 spider 进行处理;
2.4.scrapy-redis 优点
- 速度快
-- Redis 数据库是 key-value 型内存数据库,运行速度快,效率高; - 用法简单
-- scrapy-redis 是已经造好的轮子,拿来就可以用; - 去重简单
-- 使用 Redis 中的 set 类型就可以实现;
2.5. scrapy_redis 缺点
- Redis 比较吃内存;
- usage 需要处理;
参考链接:
《scrapy-redis 和 scrapy 有什么区别?》
https://www.zhihu.com/question/32302268/answer/55724369
3. scrapy-redis 的基本使用
3.1. 安装 scrapy-redis 模块
- 安装 scrapy
pip3 install scrapy
- 安装 scrapy-redis
pip3 install scrapy-redis
3.2. 安装 Redis 数据库并配置
- 安装 Redis
pip3 install redis
- 配置 Redis
vim /usr/local/etc/redis.conf
进入 vim 编辑器页面后,注释掉 bind 127.0.0.1。
# bind 127.0.0.1 # 如果不注释掉,则只能在本机上访问 Redis 数据库
3.3. 创建并编写爬虫
- 创建项目
scrapy startproject tutorial # 创建爬虫项目 tutorial
- 编写爬虫
备注:由于本文内容并非介绍 scrapy 用法,所以此处不再赘述
3.4. 修改爬虫项目文件
- 修改 spider.py
from scrapy_redis.spiders import RedisSpider
class TutorialSpider(RedisSpider): # 将爬虫的父类已经改成RedisSpider
name = "tutorialspider"
redis_key = 'tutorialspider:start_urls' # 添加的redis_key实际上是一个变量名,
# 之后爬虫爬到的所有URL都会保存到Redis中
# 这个名为“tutorialspiderspider:start_urls”
# 的列表下面,爬虫同时也会从这个列表中
# 读取后续页面的URL。
- 修改 pipeline
此处主要是修改 mysql 数据库连接,以保证所有数据都会保存于master 的 mysql 数据库,此处不做赘述;
master 上 mysql 的 host 为 127.0.0.1
slave 上 mysql 的 host 为 master 的 ip
- 修改 settings.py
-- 替换 SHCEDULER,使用 scrapy_redis 进行任务分发与调度
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
-- 使用 scrapy_redis 去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
-- 不清理爬虫队列
SCHEDULER_PERSIST = True
注意:
如果这一项为 True,那么在 Redis 中的 URL 不会被 Scrapy_redis 清理掉。
-- 这样的好处是:爬虫停止了再重新启动,它会从上次暂停的地方开始继续爬取;
-- 但是它的弊端也很明显,如果有多个爬虫都要从这里读取 URL,需要另外写一段代码来防止重复爬取;如果设置成了 False,那么 Scrapy_redis 每一次读取了 URL 以后,就会把这个 URL 给删除。
-- 这样的好处是:多个服务器的爬虫不会拿到同一个 URL,也就不会重复爬取。
-- 但弊端是:爬虫暂停以后再重新启动,它会重新开始爬。
-- 爬虫请求调度算法
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue' # 使用队列进行调度
注意:
-- 使用 ‘队列’ 进行爬虫调度
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue'-- 使用 ‘栈’ 进行爬虫调度
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'-- 使用 ‘优先级队列’ 进行爬虫调度
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'
-- 设置 Redis 地址和端口
REDIS_HOST = '127.0.0.1' # 修改为Redis的实际IP地址
REDIS_PORT = 6379 # 修改为Redis的实际端口
注意:
如果不设置 Redis 的地址和端口,系统会默认 Redis 运行在本机。
这样,就初步实现了 scrapy-redis 基本的爬虫框架。