scrapy分布式
一、分布式概述
1. 什么是分布式?
将一个任务分割成多份,每一份由一个计算机完成,最后所有的计算机能够成为一个整体,得到这个任务的结果。
分布式产生的原因:
原来一个数据库都是放在一台电脑上的,但是由于用户量的增多,造成数据库压力很大,所以产生一个思想,就是用多台电脑可以提供同样的数据库服务。
2. scrapy分布式:
原来的项目是部署在一台电脑上的,这样爬取速度虽然很快,但是我们还能提升,联想到分布式的思想,我们是否可以通过多台电脑进行配合爬取,这样我们的爬取速度就能大幅度提升。
分布式爬虫就是:【多台电脑爬取同一个项目】。
3. scrapy和scrapy-redis的区别:
- scrapy是一个爬虫框架,但是他不支持分布式。
- scrapy-redis,通过scrapy上增加一个redis组件,这个redis里面设置了带爬取url的列表和每个url的指纹集合,通过这两点,做到了分布式,使得多台电脑可以联合爬取一个任务。
二、Redis数据库及可视化工具安装
1. Redis是什么
Redis是一个由 Salvatore Sanfilippo 写的 key-value 存储系统。Redis 提供了一些丰富的数据结构,包括 lists、sets、orderedsets 以及 hashes ,当然还有和 Memcached 一样的 strings 结构。Redis 当然还包括了对这些数据结构的丰富操作。
2. 安装Redis数据库
-
windows
(1)安装包下载地址:https://github.com/microsoftarchive/redis/releases
(2)然后选择 msi 文件下载,双击安装
下载完成后双击打开安装(安装过程中一定要添加到系统环境变量)
cmd终端中输入redis-cli有如下效果表示安装配置成功
-
Linux
直接输入命令 sudo apt-get install redis-server 。安装完成后,Redis服务器会自动启动。
使用redis-cli 命令即可进入Redis数据库。 -
Mac电脑请参考如下教程:https://blog.csdn.net/wto882dim/article/details/99684311
3. 安装可视化工具
windows系统下直接双击RedisStudio-en-0.1.5.exe即可免安装使用:https://pan.baidu.com/s/1LZLpwuCSF8w5P44ubX7Txw?pwd=uinf
Mac系统参考上述链接教程
4. redis基本数据库语法
Redis 常被称作是一款数据结构服务器(data structure server)。Redis 的键值可以包括字符串(strings)类型,同时它还包括哈希(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)等数据类型。
本课中需要用到列表(lists)操作,咱们来看看常用数据库指令:
- lpush/rpush 队列左边或者右边增加内容
- lrange 获取指定长度的内容
操作截图:
其中 lpush/rpush 是在列表中添加数据的指令,mylist 是列表的名字,后面是在列表中添加的数据。
三、分布式采集
Scrapy_redis : 基于Scrapy的Redis组件
Github地址:https://github.com/rmax/scrapy-redis
Scrapy_redis 在scrapy 的基础上实现了更多,更强大的功能,具体体现在:reqeust去重,爬虫持久化,和轻松实现分布式
那么,scrapy_redis是如何帮助我们抓取数据的呢?
1. 单机爬虫
默认情况下Scrapy是不支持分布式的,需要使用基于Redis 的Scrapy-Redis 拓展组件才能实现分布式。
正常的scrapy单机爬虫:
Scrapy并不会共享调度队列,也就是说Scrapy是不支持分布式的。为了支持分布式,我们需要让Scrapy支持共享调度队列,也就是改造成共享调度和去重的功能。
2. 分布式爬虫
分布式:分而治之
将一个爬虫代码,分别部署在多台电脑上,共同完成整个爬虫任务。
使用Redis服务器来集中处理所有的请求,主要负责请求的去重和调度。通过这种方式,所有电脑端的爬虫共享了一个爬取队列,并且每个电脑端每次得到的请求都是其他爬虫未曾访问的。从而提高了爬虫效率。
得到一个请求之后,检查一下这个Request是否在Redis去重,如果在就证明其它的spider采集过啦!如果不在就添加进调度队列,等待别人获取。
Scrapy 是一个通用的爬虫框架,但是不支持分布式,Scrapy-redis是为了更方便地实现Scrapy分布式爬取,而提供了一些以redis为基础的组件。
安装如下:pip install scrapy-redis
Scrapy-redis 提供了下面四种组件(components):(四种组件意味着这四个模块都要做相应的修改)
- Scheduler(调度器)
- Duplication Filter(去重)
- Item Pipeline(管道)
- Base Spider(爬虫类)
Scheduler(调度器)
Scrapy改造了Python本来的collection.deque(双向队列)形成了自己的Scrapy queue,但是Scrapy多个spider不能共享待爬取队列Scrapy queue, 即Scrapy本身不支持爬虫分布式,scrapy-redis的解决是把这个Scrapy queue换成redis数据库(也是指redis队列),便能让多个spider去同一个数据库里读取,这样实现共享爬取队列。
Redis支持多种数据结构,这些数据结构可以很方便的实现这样的需求:
- 列表有lpush(),lpop(),rpush(),rpop(),这些方法可以实现 先进先出,或者先进后出式的爬取队列。
- 集合元素是无序且不重复的,可以很方便的实现随机排序且不 重复的爬取队列。
- Scrapy的Request带有优先级控制,Redis中的集合也是带有分 数表示的,可以用这个功能实现带有优先级调度的爬取队列。
Scrapy把待爬队列按照优先级建立了一个字典结构,比如:
{
优先级0 : 队列0
优先级1 : 队列1
优先级2 : 队列2
}
然后根据request中的优先级,来决定该入哪个队列,出列时则按优先级较小的优先出列。由于Scrapy原来的Scheduler只能处理
Scrapy自身的队列,不能处理Redis中的队列,所以原来的Scheduler已经无法使用,应该使用Scrapy-Redis的Scheduler组件。
Duplication Filter(去重)
Scrapy自带去重模块,该模块使用的是Python中的集合类型。该集合会记录每个请求的指纹,指纹也就是Request的散列值。指纹的计算采用的是hashlib的sha1()方法。计算的字段包含了,请求的Method,URL,Body,Header这几个内容,这些字符串里面只要里面有一点不同,那么计算出来的指纹就是不一样的。也就是说,计算的结果是加密后的字符串,这就是请求指纹。通过加密后的字符串,使得每个请求都是唯一的,也就是指纹是惟一的。并且指纹是一个字符串,在判断字符串的时候,要比判断整个请求对象容易。所以采用了指纹作为判断去重的依据。
Scrapy-Redis要想实现分布式爬虫的去重功能,也是需要更新指纹集合的,但是不能每个爬虫维护自己的单独的指纹集合。利用
Redis集合的数据结构类型,可以轻松实现分布式爬虫的指纹判重。也就是说:每台主机得到Request的指纹去和Redis中的集合进行对比,如果指纹存在,说明是重复的,也就不会再去发送请求,如果不曾存在于Redis中的指纹集合,就会发送请求,并且将该指纹加入Redis的集合中。这样就实现了分布式爬虫的指纹集合的共享。
Item Pipeline
引擎将(Spider返回的)爬取到的Item给Item Pipeline,scrapyredis 的Item Pipeline将爬取到的 Item 存⼊redis的 items queue。修改过Item Pipeline可以很方便的根据 key 从 items queue 提取item,从⽽实现 items processes集群。
Base Spider
不再使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url
的类。当我们生成一个Spider继承RedisSpider时,调用setup_redis函数,这个函数会去连接redis数据库,然后会设置signals(信号):
当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,
并且抛出DontCloseSpider异常。
当抓到一个item时的signal,会调用item_scraped函数,这个函数会调用schedule_next_request函数,获取下一个request。
3. Scrapy_redis
- clone github scrapy-redis源码文件
git clone https://github.com/rmax/scrapy-redis.git
- 研究项目自带的三个demo
domz
# filename(spider):domz.py
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class DmozSpider(CrawlSpider):
"""Follow categories and extract links."""
name =