Scrapy:使用 Scrapy-redis 搭建 master-slave 主从分布式爬虫系统

1. 分布式爬虫简介

1.1. 分布式系统介绍

  • 分布式概念
    -- 分布式系统是由一组多台计算机组成的系统;
    -- 计算机之间通过网络进行通信;
    -- 计算机之间为完成共同的任务而协调工作;
    -- 分布式系统的目的是为了利用更多的机器,处理更多的数据,完成更多的任务;
  • 分布式系统的实现
    -- 分布式系统的实现包括 MapReduceReplication
    -- 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 架构图:


    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 基本的爬虫框架。

你可能感兴趣的:(Scrapy:使用 Scrapy-redis 搭建 master-slave 主从分布式爬虫系统)