zoukankan      html  css  js  c++  java
  • Scrapy Redis

    Scrapy Redis

    Scrapy自带的待爬队列是deque,而现在需要使用Redis来作为队列,所以就需要将原来操作deque的方法替换为操作Redis的方法。当你把三轮车换成挖掘机的时候,驾驶员肯定是要更换的。Scrapy_redis在这里就是充当驾驶员的角色。更准确的说,Scrapy_redis是Scrapy的“组件”,它已经封装了使用Scrapy 操作Redis的各个方法。


    安装

    使用pip安装:

    $ pip install scrapy_redis

    在使用Scrapy_redis之前,先来讲一讲它的原理。

    在Redis中,有一个数据结果叫做“列表”。这个列表和 Python 的列表很相似,可以添加数据进去,也可以从里面读取数据或者删除元素。

    在下图的例子中,创建一个名字叫做 spider 的列表,从列表的尾部添加了三个元素:“hotstone”, "shilei" 和 "slzcc",然后再从列表的头部一个一个元素的读取并删除。

    127.0.0.1:6379> lrange spider 0 -1
    (empty list or set)
    127.0.0.1:6379> rpush spider 'hotstone'
    (integer) 1
    127.0.0.1:6379> rpush spider 'shilei'
    (integer) 2
    127.0.0.1:6379> rpush spider 'slzcc'
    (integer) 3
    127.0.0.1:6379> lrange spider 0 -1
    1) "hotstone"
    2) "shilei"
    3) "slzcc"
    127.0.0.1:6379> lpop spider
    "hotstone"
    127.0.0.1:6379> lpop spider
    "shilei"
    127.0.0.1:6379> lpop spider
    "slzcc"

    在 Scrapy_redis 中,也是使用了这个原理,Scrapy 通过:

    yield scrapy.Request(URL, callback=xxxx)

    这一个语句将URL放到Redis的队列中,然后在生成器中的代码被执行的时候再去Redis中取这个URL。如果多个服务器的爬虫都从Redis中读取URL的话,这就是分布式爬虫。

    Scrapy_redis 的使用

    由于Scrapy_redis已经为封装了大部分的流程,所以使用它不会有任何难度。

    修改爬虫

    爬虫是继承自scrapy.Spider这个父类。这是Scrapy里面最基本的一个爬虫类,只能实现基本的爬虫功能。现在需要把它替换掉,从而实现更高级的功能。

    请对比一下下面这段使用了Scrapy_redis的代码与前面read color网站爬虫的代码头部有什么不同:

    from scrapy_redis.spiders import RedisSpider
     
    class ReadColorSpider(RedisSpider):
        name = "zhihuspider"
        redis_key = 'zhihuspider:start_urls'

    可以看出,这里爬虫的父类已经改成了RedisSpider,同时多了一个:

    redis_key = 'zhihuspider:start_urls'

    这里的redis_key实际上就是一个变量名,之后爬虫爬到的所有URL都会保存到Redis中这个名为“zhihuspider:start_urls”的列表下面,爬虫同时也会从这个列表中读取后续页面的URL。这个变量名可以任意修改。

    除了这两点以外,在爬虫部分的其他代码都不需要做修改。

    实际上,这样就已经建立了一个分布式爬虫,只不过现在只有一台电脑。

    修改设置

    现在已经把三轮车换成了挖掘机,但是Scrapy还在按照指挥三轮车的方式指挥挖掘机,所以挖掘机还不能正常工作。因此修改爬虫文件还不行,Scrapy还不能认识这个新的爬虫。现在修改settings.py。

    (1)Scheduler

    首先是Scheduler的替换,这个东西是Scrapy中的调度员。在settings.py中添加以下代码:

    # Enables scheduling storing requests queue in redis.
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"

    (2)去重

    # Ensure all spiders share same duplicates filter through redis.
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

    设置好上面两项以后,爬虫已经可以正常开始工作了。不过还可以多设置一些东西使爬虫更好用。

    (3)不清理Redis队列

    # Don't cleanup redis queues, allows to pause/resume crawls.
    SCHEDULER_PERSIST = True

    如果这一项为True,那么在Redis中的URL不会被Scrapy_redis清理掉,这样的好处是:爬虫停止了再重新启动,它会从上次暂停的地方开始继续爬取。但是它的弊端也很明显,如果有多个爬虫都要从这里读取URL,需要另外写一段代码来防止重复爬取。

    如果设置成了False,那么Scrapy_redis每一次读取了URL以后,就会把这个URL给删除。这样的好处是:多个服务器的爬虫不会拿到同一个URL,也就不会重复爬取。但弊端是:爬虫暂停以后再重新启动,它会重新开始爬。

    爬虫请求的调度算法

    爬虫的请求调度算法,有三种情况可供选择:

    • 队列
    SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue'

    如果不配置调度算法,默认就会使用这种方式。它实现了一个先入先出的队列,先放进Redis的请求会优先爬取。

    SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'

    这种方式,后放入到Redis的请求会优先爬取。

    • 优先级队列
    SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'

    这种方式,会根据一个优先级算法来计算哪些请求先爬取,哪些请求后爬取。这个优先级算法比较复杂,会综合考虑请求的深度等各个因素。

    【拓展阅读】

    Redis信息,如果不配置的话,Scrapy_redis会默认Redis就运行在现在这台电脑上,IP和端口也都是默认的127.0.0.1和6379。如果Redis不在本地的话,就需要将它们写出来:

    REDIS_HOST = '127.0.0.1' #修改为Redis的实际IP地址
    REDIS_PORT = 6379 #修改为Redis的实际端口

    代码展示:

    爬虫的运行.zip

    修复 BUG 

    如果出现了 scrapy_redis 字符串报错的信息请修改,路径有可能不一样,这里使用 Macbook brew 安装后的路径:

    /usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/scrapy_redis/spiders.py

    中添加,如图

    data = data.decode()

    配置文件讲解

    #启用Redis调度存储请求队列SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      
    #确保所有的爬虫通过Redis去重
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      
    #默认请求序列化使用的是pickle 但是我们可以更改为其他类似的。PS:这玩意儿2.X的可以用。3.X的不能用
    #SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"
      
    #不清除Redis队列、这样可以暂停/恢复 爬取
    #SCHEDULER_PERSIST = True
      
    #使用优先级调度请求队列 (默认使用)
    #SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
    #可选用的其它队列
    #SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'
    #SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'
      
    #最大空闲时间防止分布式爬虫因为等待而关闭
    #SCHEDULER_IDLE_BEFORE_CLOSE = 10
      
    #将清除的项目在redis进行处理
    ITEM_PIPELINES = {
        'scrapy_redis.pipelines.RedisPipeline'300
    }
      
    #序列化项目管道作为redis Key存储
    #REDIS_ITEMS_KEY = '%(spider)s:items'
      
    #默认使用ScrapyJSONEncoder进行项目序列化
    #You can use any importable path to a callable object.
    #REDIS_ITEMS_SERIALIZER = 'json.dumps'
      
    #指定连接到redis时使用的端口和地址(可选)
    #REDIS_HOST = 'localhost'
    #REDIS_PORT = 6379
      
    #指定用于连接redis的URL(可选)
    #如果设置此项,则此项优先级高于设置的REDIS_HOST 和 REDIS_PORT
    #REDIS_URL = 'redis://user:pass@hostname:9001'
      
    #自定义的redis参数(连接超时之类的)
    #REDIS_PARAMS  = {}
      
    #自定义redis客户端类
    #REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient'
      
    #如果为True,则使用redis的'spop'进行操作。
    #如果需要避免起始网址列表出现重复,这个选项非常有用。开启此选项urls必须通过sadd添加,否则会出现类型错误。
    #REDIS_START_URLS_AS_SET = False
      
    #RedisSpider和RedisCrawlSpider默认 start_usls 键
    #REDIS_START_URLS_KEY = '%(name)s:start_urls'
      
    #设置redis使用utf-8之外的编码
    #REDIS_ENCODING = 'latin1'

    官方地址介绍:http://scrapy-redis.readthedocs.io/en/stable/readme.html

    相关文档:http://cuiqingcai.com/4048.html

  • 相关阅读:
    自用类库整理之SqlHelper和MySqlHelper
    如何设置root登录(滴滴云)
    linux下载命令wget
    linux下查看已经安装的jdk 并卸载jdk
    Angular之constructor和ngOnInit差异及适用场景(转)
    【Spring Boot-技巧】API返回值去除为NULL的字段
    jackson 实体转json 为NULL或者为空不参加序列化
    Android 将Android项目打包成aar文件
    Linux修改war包中文件
    Android 7.0 Gallery图库源码分析4
  • 原文地址:https://www.cnblogs.com/dalton/p/11353871.html
Copyright © 2011-2022 走看看