distributed crawler based on scrapy-redis and docker

初步编写 #

记录一次典型多坑的分布式爬虫项目开发过程,经过了两次重构。分布式爬虫的整体思路是将 start_url 存入 redis ,便于后续的并发爬取,用 docker 进行部署, kubernates 管理容器,仓库使用 harbor

对于某站进行全量爬取,有三层深度分为省份、地区、品牌。由于我们需要的详情数据在叶节点,需要省份、地区、品牌的标签,依靠遍历去搜索的思路: 省份约 30 x 地区约 20 x 品牌约 170 * 2 * 若干页码 = 20 w 。遍历的思路明显是冗余的,仔细寻找接口,分析页面后,详情页内寻找到对应的一个用于其他查询但可靠的 api 。但没有发现地区的字段。因为还有一个需求是获取经纬度,调用百度 api 即可全部解决。这样通过获取详情页,寻找接口,避免了循环遍历,复杂度仅为 5 w。

这样出现了在一个请求事件中需要调用多个接口的情况,一般是想通过 meta 字典来传值,通过 scrapy 来实现请求和解析,有没有更好的写法?

但我最终选择了第四种方法,跳出 scrapy 框架,原因有:

scrapy-redis 的优点在于分布式、代理池、拓展性好。我们的额外请求不需要1、3,因此额外写一个可接受代理池的 utils 模块即可。

在考虑并发时,虽然按照异步编程的思想,不应该把同步事件写到异步事件中,但在这个例子中,对于每个单个 api 的处理网络良好,阻塞不会很久,而且为了易于调试和维护,即写在一个request请求中。

第一次重构 #

优化爬虫 #

将原来爬虫获取详情 url 和解析详情页分开编写为两个爬虫,中间数据插入到 redis
目的是便于调试,调整请求队列加快并发速度(解析详情页)。

低耦合 #

为两个爬虫都自定义 commands
第一个爬虫的插入 url 命令单独作为一个脚本,两个爬虫启动命令分别写在 Dockerfile 中。

第二次重构 #

增强代码鲁棒性 #

查看日志提取错误信息,发现存在错误:

在每个地方都加入了判断和重试,并且允许为空。

优化项目 #

在整个项目层面上进行优化,不只针对爬虫逻辑。

将并发量降低为 2,原因是那个网站服务器太差了,两次把服务器爬炸了... 只有部分类似的请求出现超时和无响应,猜测是他的后台读取数据库阻塞的问题。

降低每个爬虫的并发量,提高容器组个数,把并发交给容器而不是单个 scrapy (背后是 twisted )去处理队列和多线程。

把两个网站爬虫分为两个容器组,这样可以伸缩容器便于管理资源。

End.💖

Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated! If any questions, plz contact me!

Published