zoukankan      html  css  js  c++  java
  • scrapy-redis 实现分布式爬虫

     分布式爬虫

    一 介绍

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

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

    #1、共享队列
    #2、重写Scheduler,让其无论是去重还是任务都去访问共享队列
    #3、为Scheduler定制去重规则(利用redis的集合类型)

    以上三点便是scrapy-redis组件的核心功能

    #安装:
    pip3 install scrapy-redis
    
    #源码:
    D:python3.6Libsite-packagesscrapy_redis

    二、scrapy-redis组件

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

     

    复制代码
    #一、源码:D:python3.6Libsite-packagesscrapy_redisdupefilter.py
    
    
    
    #二、配置scrapy使用redis提供的共享去重队列
    
    #2.1 在settings.py中配置链接Redis
    REDIS_HOST = 'localhost'                            # 主机名
    REDIS_PORT = 6379                                   # 端口
    REDIS_URL = 'redis://user:pass@hostname:9001'       # 连接URL(优先于以上配置)
    REDIS_PARAMS  = {}                                  # Redis连接参数
    REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定连接Redis的Python模块
    REDIS_ENCODING = "utf-8"                            # redis编码类型  
    # 默认配置:D:python3.6Libsite-packagesscrapy_redisdefaults.py
    
    #2.2 让scrapy使用共享的去重队列
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    #使用scrapy-redis提供的去重功能,查看源码会发现是基于Redis的集合实现的
    
    #2.3、需要指定Redis中集合的key名,key=存放不重复Request字符串的集合
    DUPEFILTER_KEY = 'dupefilter:%(timestamp)s'
    #源码:dupefilter.py内一行代码key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
    
    #2.4、去重规则源码分析dupefilter.py
    def request_seen(self, request):
        """Returns True if request was already seen.
    
    ```
    Parameters
    ----------
    request : scrapy.http.Request
    
    Returns
    -------
    bool
    
    """
    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
    ```
    
    #2.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)
    print(result) #75d6587d87b3f4f3aa574b33dbd69ceeb9eafe7b
    
    #2.6、注意:
        - 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
    ```
    复制代码

    2、使用scrapy-redis的去重+调度实现分布式爬取

    View Code

    3、持久化

    复制代码
    #从目标站点获取并解析出数据后保存成item对象,会由引擎交给pipeline进行持久化/保存到数据库,scrapy-redis提供了一个pipeline组件,可以帮我们把item存到redis中
    
    #1、将item持久化到redis时,指定key和序列化函数 
    REDIS_ITEMS_KEY = '%(spider)s:items'
    REDIS_ITEMS_SERIALIZER = 'json.dumps'
    
    #2、使用列表保存item数据
    复制代码

    4、从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
    复制代码
     注意:我们在启动爬去任务main 服务端开启 时 必须在cmd 中执行客服端请求的url 签入命令 请求数据
    # lpush cnblogs:start_urls https://www.cnblogs.com  》》》 我们启动的是redis 中的url
  • 相关阅读:
    越来越火的5G公网专用,到底是啥意思?
    看懂IPv6+,这篇就够了
    今年诺贝尔奖得主居然把这事研究清楚了:学历和收入到底有多大关系?
    华为发布《智能世界2030》报告,多维探索未来十年趋势
    每天一个离职小技巧
    Deepsort + Yolo 实现行人检测和轨迹追踪
    “5G+AI”到底有啥用?这篇漫画告诉你答案…
    全国多地拉闸限电 背后到底怎么了?
    【Ajax请求 】- 1.1前端和后台数据交互的说明
    【Web API系列教程】3.3 — 实战:处理数据(建立数据库)
  • 原文地址:https://www.cnblogs.com/mofujin/p/11960990.html
Copyright © 2011-2022 走看看