分布式爬虫

分布式爬虫

介绍

原来scrapy的Scheduler维护的是本机的任务队列(存放Request对象及其回调函数等信息)+本机的去重队列(存放访问过的url地址)

在这里插入图片描述

所以实现分布式爬取的关键就是,找一台专门的主机上运行一个共享的队列比如Redis,
然后重写Scrapy的Scheduler,让新的Scheduler到共享队列存取Request,并且去除重复的Request请求,所以总结下来,实现分布式的关键就是三点:

  1. 共享队列
  2. 重写Schedule, 让其无论式去重还是人去都去访问共享队列
  3. 为Schedule定制去重规制(利用redis的集合类型)
    在这里插入图片描述
安装
	pip install scrapy-redis

scrapy-redis组件

  1. 只使用scrapy-redis的去重功能

在这里插入图片描述

  1. 配置scrapy使用redis提供的共享去重队列
1. 在settings.py中配置链接Redis
    REDIS_HOST = 'localhost'                            # 主机名
    REDIS_PORT = 6379                                   # 端口
    本地链接以上两项就够了
    REDIS_URL = 'redis://user:pass@hostname:9001'       # 连接URL(优先于以上配置)
    # REDIS_URL 等同于 REDIS_HOST+REDIS_PORT+ 写一个即可
    REDIS_PARAMS  = {'password': ''}                    # Redis连接参数,密码写在这里面
    REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定连接Redis的Python模块
    REDIS_ENCODING = "utf-8"                            # redis编码类型 
2. 让scrapy使用共享的去重队列
	DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
	# 使用scrapy-redis提供的去重功能,查看源码会发现是基于Redis的集合实现的
3. 需要指定Redis中集合的key名,key=存放不重复Request字符串的集合
	DUPEFILTER_KEY = 'dupefilter:%(timestamp)s'
    # 源码:dupefilter.py内一行代码 key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
4. 去重规则源码分析dupefilter.py    
    def request_seen(self, request):
        fp = self.request_fingerprint(request) 
        # This returns the number of values added, zero if already exists.
        added = self.server.sadd(self.key, fp)
        return added == 0  
5. 将request请求转成一串字符后再存入集合    
    from scrapy.http import Request
    from scrapy.utils.request import request_fingerprint
    req = Request(url='http://www.baidu.com')
    result=request_fingerprint(req)
注意:
    - URL参数位置不同时,计算结果一致;
    - 默认请求头不在计算范围,include_headers可以设置指定请求头
    - 示范:
    from scrapy.utils import request
    from scrapy.http import Request
     
req = Request(url='http://www.baidu.com?name=8&id=1',callback=lambda x:print(x),cookies={'k1':'vvvvv'})
result1 = request.request_fingerprint(req,include_headers=['cookies',])
 
print(result)
 
req = Request(url='http://www.baidu.com?id=1&name=8',callback=lambda x:print(x),cookies={'k1':666})
 
result2 = request.request_fingerprint(req,include_headers=['cookies',])
 
print(result1 == result2) #True
  1. 使用scrapy-redis的去重+调度实现分布式爬取
1. settings.py配置
SCHEDULER = "scrapy_redis.scheduler.Scheduler" 
# 去重规则对应处理的类,将任务request_fingerprint(request)得到的字符串放入去重队列 
SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
--------------------配置以上两项即即可使用-----------------------------
# 调度器将不重复的任务用pickle序列化后放入共享任务队列,默认使用优先级队列(默认),其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表)               
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'          
# 对保存到redis中的request对象进行序列化,默认使用pickle
SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"   
# 调度器中请求任务序列化后存放在redis中的key               
SCHEDULER_QUEUE_KEY = '%(spider)s:requests' 
# 是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空                     
SCHEDULER_PERSIST = True       
# 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空
SCHEDULER_FLUSH_ON_START = False    
# 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。如果没有则立刻返回会造成空循环次数过多,cpu占用率飙升                                
SCHEDULER_IDLE_BEFORE_CLOSE = 10           
# 去重规则,在redis中保存时对应的key                         
SCHEDULER_DUPEFILTER_KEY = '%(spider)s:dupefilter'
 
2. 爬虫中原来继承Spider, 现在继承RedisSpider
3. 将start_urls = ['https:/www.cnblogs.com/']
   换成redis_key = 'myspider:start_urls'
    from scrapy_redis.spiders import RedisSpider
    lass CnblogSpider(RedisSpider):
    name = 'cnblog_redis'
    allowed_domains = ['www.cnblogs.com']
    # start_urls = ['https:/www.cnblogs.com/']
    redis_key = 'myspider:start_urls'
4. 配置完启动爬虫即可         
  1. 持久化
#从目标站点获取并解析出数据后保存成item对象,会由引擎交给pipeline进行持久化/保存到数据库,scrapy-redis提供了一个pipeline组件,可以帮我们把item存到redis中
1. 将item持久化到redis时,指定key和序列化函数(持久化看需配置)
    ITEM_PIPELINES = {
       'scrapy_redis.pipelines.RedisPipeline': 300
    }
    REDIS_ITEMS_KEY = '%(spider)s:items'   # 默认即可
    REDIS_ITEMS_SERIALIZER = 'json.dumps'   # 默认即可
2. 使用列表保存item数据
  1. 从Redis中获取起始URL
scrapy程序爬取目标站点,一旦爬取完毕后就结束了,如果目标站点更新内容了,我们想重新爬取,那么只能再重新启动scrapy,非常麻烦
scrapy-redis提供了一种供,让scrapy从redis中获取起始url,如果没有scrapy则过一段时间再来取而不会关闭
这样我们就只需要写一个简单的脚本程序,定期往redis队列里放入一个起始url即可。

#1、编写爬虫时,起始URL从redis的Key中获取
REDIS_START_URLS_KEY = '%(name)s:start_urls'
    
#2、获取起始URL时,去集合中获取还是去列表中获取?True,集合;False,列表
REDIS_START_URLS_AS_SET = False    # 默认即可
# 获取起始URL时,如果为True,则使用self.server.spop;如果为False,则使用self.server.lpop

补充

# 爬虫的防爬措施总结
	1 user-agent  
    2 referer
    3 cookie	(使用cookie池)
    4 频率限制	(使用代理池或者延迟)
    5 js加密	(扣出来,exjs模块执行或者自己写)
    6 css加密
    7 验证码(打码平台),半手动
    8 图片懒加载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值