一.概述:分布式爬虫
分布式爬虫:多台电脑一起爬取数据
单机爬虫:一台电脑自己爬取数据
分布式爬虫的优点:1.充分利用多台机器的带宽加速爬取;2.充分利用多台机子的IP来爬取,总而言之,十个人干活肯定比一个人干活来的快和好
那么,当同一个爬虫程序在多台电脑上同步爬取数据,如何保证A电脑爬取的数据,在B电脑上不会重复爬取.
这就需要统一的状态的管理器(redis)来统一管理,主要承担request的队列的调度与去重等功能
二.概述:redis
redis的本质是内存数据库,key-value存储系统
它支持的value类型有:string, list, set, zset(有序集合), hash(字典)
github上搜索redis-windows
即可下载zip包
set course "scrapy-redis" #string
get course
getrange course 2 4 #获取字符串子串
strlen course #获取字符串长度
incr count #针对整型或者可以转换成整型的str,做加1操作
decr count #同上,减1
append course aaa #原str末尾追加字符串
hset course_dict egg "scrapy-redis" #hset-->字典
hget course_dict egg #返回字典键对应的值
hgetall course_dict #返回字典的键和值
hexists course_dict egg #返回0或1,代表键是否存在,1为存在
hdel course_dict egg #删除键值
hkeys course_dict #返回所有的键
hvals course_dict #返回所有的值
lpush courses django #从列表的左边插入,即:列表表头插入
rpush courses redis #同上,从列表的右边插入
lrange courses 0 10 #查看列表前10个,10超过列表长度不会报错
blpop courses 3 #从列表左边开始删除1个值,3代表3秒,如果对应列表有则直接删除,如果没有则会等待3秒,b代表阻塞
brpop course 3 #同上
lpop key #从列表左边开始删除1个值
rpop key #从列表右边开始删除1个值
llen courses #返回列表长度
lindex courses 0 #返回列表第0个元素
sadd course_set django #无序set,返回0/1,1代表集合里面没有并放入集合,0代表集合里面有了
scard course_set #返回集合的长度
sdiff set1 set2 #集合相减,减掉交集
sinter set1 set2 #集合求交集
spop course_set #随机删除一个元素并将其返回
srandmember course_set 3#随机获取3个元素
smembers course_set #获得集合内所有的元素
zadd myset 0 django 1 scrapy 5 redis 10 python #有序集合
zrangebyscore myset 0 100 #返回分数为0到100之间的值
zcount myset 0 100 #返回分数为0到100之间的值的个数
keys * #查看所有所有的键
type key #查看键对应value的类型
三.scrapy-redis搭建分布式爬虫
github上搜索scrapy-redis
https://github.com/rmax/scrapy-redis
将下载下来的包里面的src下的scrapy-redis
文件夹拷贝到自己的项目下
另外安装redis的驱动:pip install redis
我们以scrapy-redis里面的example为例来介绍
第一步:自己写的spider程序继承RedisSpider
,然后原先爬取的逻辑该怎么写还怎么写
from scrapy_redis.spiders import RedisSpider
class MySpider(RedisSpider): # 继承RedisSpider
"""Spider that reads urls from redis queue (myspider:start_urls)."""
name = 'myspider_redis'
redis_key = 'myspider:start_urls'
def __init__(self, *args, **kwargs):
# Dynamically define the allowed domains list.
domain = kwargs.pop('domain', '')
self.allowed_domains = filter(None, domain.split(','))
super(MySpider, self).__init__(*args, **kwargs)
def parse(self, response):
return {
'name': response.css('title::text').extract_first(),
'url': response.url,
}
第二步:setting配置修改如下
# 把scrapy中默认的调度器替换成scrapy-redis中的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 把scrapy中默认的去重组件替换为scrapy-redis中的去重组件
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 添加scrapy-redis管道
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}
# 添加redis数据库的连接URL
# REDIS_URL = 'redis://127.0.0.1:6379'
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_PARAMS = {}
REDIS_PARAMS['password'] = '12345'
第三步:redis客户端里面将初始的url lpush
到队列中,key是第一步中指定的redis_key
,然后就可以启动项目
程序在redis中会生成一个requests的有序集合,和一个dupefilter的去重器; requests中存放的请求是一个序列化好的请求对象
四.源码简单解析
1.connection.py: 用于建立redis连接
2.defaults.py: 定义一些默认的值
3.dupefilter.py: 去重的文件,可以对照scrapy的dupefilter来分析;
简而言之,初始化的时候,对象中含有redis的链接,调用request的request_fingerprint方法将url转换成固定长度的字符串,然后放到redis的集合中,如果集合中存在则返回true.最终使用redis的集合实现去重
4.picklecompat.py: 调用pickle进行序列化
5.pipelines.py: 将item序列化后放到redis当中.关于这里的pipeline也可以不设置,直接保存在本地的数据库中,看实际的需要
6.queue.py: 供scheduler使用的,提供三种队列:先进先出,先进后出,优先级队列
7.scheduler.py: 这个文件要对应scrapy的scheduler.py来一起分析
视频教程
相应的视频教程在这里 https://mp.weixin.qq.com/s/DG-T965Y9yKLwNYPus2cXA
本文由 mdnice 多平台发布