scrapy源码阅读笔记(2) -- scheduler

数据流向

《scrapy源码阅读笔记(2) -- scheduler》

关于Scheduler

Scheduler主要负责scrapy请求队列的管理,即进队与出队。进一步来说,会涉及到队列的选择,队列去重,序列化。

属性/方法功能描述
df去重模块默认利用set在内存去重
dqdir磁盘队列路径持久化队列至硬盘
pqclass带优先级队列默认来自queuelib
dqclass磁盘队列持久化队列至硬盘
mqclass内存队列默认来自queuelib
stats状态记录状态记录通用模块
from_crawler实例化入口scrapy风格的实例化入口
has_pending_requests检查队列数指向len
open初始化队列scrapy模块的初始化入口
close安全退出接口scrapy模块的安全入口
enqueue_request进队api调度进队
next_request出队api调度出队

另外,enqueue_request next_request 封装了一些内部函数,指向queue。

去重 scrapy.dupefilters.RFPDupeFilter

class RFPDupeFilter(BaseDupeFilter):

    def request_seen(self, request):
        fp = self.request_fingerprint(request)
        if fp in self.fingerprints:
            return True
        self.fingerprints.add(fp)
        if self.file:
            self.file.write(fp + os.linesep)

    def request_fingerprint(self, request):
        return request_fingerprint(request)

scrapy默认去重方案:

  • 利用request生成fingerprint, 存入set
  • 每次利用set判断
  • 如果用了 disk queue 追加至文件

request_fingerprint默认采用的hashlib.sha1,利用headers/method/url/body生成

队列 queuelib

包含了一些基本的队列FIFO/LIFO, 以及带有优先级的PriorityQueue。Github 上有功能用法介绍

爬取策略

针对不同的场景可能会选择不同的队列。

  • FIFO 先进先出, 队列针对时间顺排
  • LIFO 后进先出, 队列针对时间倒排
  • DFS 深度优先, 针对depth(按照referer建立树的深度)倒排
  • BFS 广度优先, 针对depth(按照referer建立树的深度)顺排
    在scrapy的文档中有介绍如何设置各种队列。在frontera中也是以这几种策略为基础,生成scoring log

值得一提的是,在网站数目较多的时候(200~500)个, 这些策略的稳定性都不是很好,(控制单个域名访问频率)亲测都有一定概率遭遇队列阻塞。刚开始下载量可以到1200 page/min, 渐渐降低到300~500, 谈不上慢,但总有些损耗。

域名队列

为了解决域名阻塞的问题,chamilto设计了域名队列去改进, 基本思路

  • 发现新增域名时即建立域名-队列映射/域名队列/request队列
  • 索取新request之前, 先访问域名队列, 再根据映射表访问该域名下的requet

代码实现上,需要修改schduler初始化参数,重载进队出队相关的内部函数。对于内存队列, 性能不是问题, 对于持久化队列(硬盘/数据库)IO压力会增大

序列化

在做队列(对象)持久化/传输时会用到.常见的方案如下

  • cpickle/json
  • 逐个字段转换,存入数据库

对于scrapy的disk queue来说

scrapy.utils.reqser.request_to_dict 将request转成dict
scrapy.squeues.PickleFifoDiskQueue 做序列化队列

    原文作者:troy_ld
    原文地址: https://www.jianshu.com/p/a3481b4bb4db
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞