https://www.jianshu.com/p/4a1d598315ed
概述
历时大致两个月, 到现在终于完成了高可用分布式代理 IP 池 (https://github.com/SpiderClub/haipproxy), 目前开源在了 Github 上写这个项目的原因主要有两点, 一是自己平时的部分工作需要和爬虫打交道, 代理 IP 在有的时候可以发挥非常重要的作用, 调研过一些开源的代理 IP 采集程序, 发现在抓取解析校验资源调度等这些方面总有一些不尽人意的地方; 二是和一个网友(不严格的说算得上是伯乐) 的交流让我有了关于使用 Scrapy 来写分布式爬虫的一些想法, 正好可以借助这个机会来尝试证实这些想法
架构设计
这篇文章的目的是阐述 haipproxy 的主要架构和流程该项目关键部分是
基于 Scrapy 和 Redis 的分布式爬虫, 用作 IP 抓取和校验, 对应于项目的 crawler
基于 Redis 实现的分布式任务调度工具, 对应于项目的 scheduler 和 redis_util.py
Crawler 分为代理抓取和校验, 两者实现思想类似, 主要使用 Scrapy 的 spider_idle 信号和 DontCloseSpider 异常来阻止 Scrapy 在没有数据的时候关闭, 灵感来自 scrapy-redis(https://github.com/rmax/scrapy-redis)为了方便阐述, 我画了一张包含各个组件的流程图, 如下
haipproxy workflow
启动调度器, 包括代理爬虫调度器和校验爬虫调度器调度器会读取 rules.py 中待抓取的网站, 将其编排成任务存入各个任务队列中
启动各个爬虫, 包括 IP 抓取和校验程序项目中爬虫和调度器都是高可用的, 可以根据实际情况进行分布式部署, 无需改动代码由于本文的目标不是写成该项目的详细使用文档, 所以省略了如指定启动爬虫类型和调度器类型的介绍
代理 IP 采集爬虫启动后会到对应的任务队列中获取任务并执行, 再把获取到的结果存入一个 init 队列中
init 队列由一个特殊的校验器
HttpbinInitValidator
进行消费, 它会过滤掉透明代理, 再把可用代理输入各个 Validated 队列中
调度器会定时从 Validated 队列中获取代理 IP, 再将其存入一个临时的队列这里用一个临时队列是为了让校验更加公平, 如果直接从 Validated 队列中获取资源进行校验, 那么会增大不公平性
这时候各个校验器 (非 init 校验器) 会从对应的临时队列中获取待校验的 IP 并对其进行校验, 此处省略校验细节
校验完成后再将其放回到 Validated 队列中, 等待下一轮校验
请求成功率 (体现为分数) 响应速度和最近校验时间满足 settings.py 所配置要求的代理 IP 将会被爬虫客户端所消费
为了屏蔽各个调用语言的差异性, 目前实现的客户端是 squid 客户端, 它可以作为爬虫客户端的中间件
到此, 整个流程便完了
效果测试
以单机模式部署 haipproxy 和测试代码(https://github.com/SpiderClub/haipproxy/blob/master/examples/zhihu/zhihu_spider.py), 以知乎为目标请求站点,
每一万条成功请求为统计结果, 实测抓取效果如下
可见 haipporxy 的代理效果还算不错, 在开始的时候可以达到 1w/hour 的请求量, 几个小时候请求量请求量
降为了 5k/hour 降低的结果可能有三个:
(1)随着数据量的增大, Redis 的性能受到了一定的影响;
(2)知乎校验器在把 Init Queue 中的代理消费完之后, 由于是定时任务, 所以导致某段时间内新鲜的 IP 空缺而免费 IP 大多数都是短效的, 所以这段时间出现了 IP 的空缺;
(3)由于我们采用的是 greedy 模式调用 IP, 它的调用策略是: 高质量代理 IP 会一直被调用直至该代理 IP 不能用或者被封, 而低应速度 IP 会轮询调用这也可能导致高质量 IP 的空缺
可见 IP 校验和调用策略还有很大的优化空间希望志同道合的朋友加入进来一起优化, 这也挺有意思的
来源: http://www.92to.com/bangong/2018/03-16/33446007.html