公众号:uncle39py

V1

2022/10/24阅读:25主题:默认主题

19.爬虫:scrapy-redis分布式爬虫

一.概述:分布式爬虫

分布式爬虫:多台电脑一起爬取数据

单机爬虫:一台电脑自己爬取数据

分布式爬虫的优点: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

分类:

后端

标签:

后端

作者介绍

公众号:uncle39py
V1