美文网首页
scrapy运行定量爬虫

scrapy运行定量爬虫

作者: Python成长路 | 来源:发表于2020-05-21 15:10 被阅读0次

假设需求

现在大概有三千个scrapy的爬虫文件,10台机器,如何合理的分配爬虫?什么,这么简单的数学题还要问,一台机器分300个爬虫不就行了。确实,这样分配最简单也最直接,但会带来一些问题。就比如,有些站点网页少而有些网站很大,每个爬虫运行的时间是不一样的,最后可能导致一台累死,九台围观。而且一台机器同时运行300个爬虫,在硬件资源上的消耗会很大,也可能会导致很多爬虫无法正常运行,所以即使是这样分配爬虫我们也要限制同时运行的爬虫数量。当某个爬虫运行完了,才执行下一个。

解决方法

可以先创建出一个队列,队列里存放待抓取的爬虫(通常会创建三个,分别是pending(待抓取)、running(正抓取)、finished(已抓取))。然后每台机器开始都取指定数量的爬虫运行,当其中一个运行完,在去任务队列里取,直到队列空了。

实现

这种数量不多的队列使用Redis的集合就行,我们创建pending、running、finished三个集合,然后将所有的爬虫的name字段存放在pending集合中(当然爬虫文件名也可以,只是启动爬虫的方式稍微不一样),接着我们就可以写个脚本来运行爬虫了。
方式有两种:

一、crawl命令

伪代码:

pending.add(所有爬虫)
while True:
    if  len(running) < 指定数量:
        spider = pending.pop()
        多进程执行:f'scrapy crawl {spider}'
    else:
        time.sleep(指定时间)

然后只要编写一个extension来同步爬虫状态到Redis里

class SpiderCountLimit:

    def __init__(self, count):
        self.spider_count = count
        self.r = redis.Redis(decode_responses=True)

    @classmethod
    def from_crawler(cls, crawler):
        count = crawler.settings.get('SPIDER_COUNT', 20)
        ext = cls(count)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
        return ext

    def spider_closed(self, spider, reason):
        self.r.srem('running', spider.name) # 爬虫关闭时,删除running中的爬虫
        self.r.sadd('finished', spider.name) # 加入到已完成队列

    def spider_opened(self, spider):
        self.r.sadd('running', spider.name) # 添加爬虫到running中

这种方法就不多说了,因为我没尝试,直接看第二种

二、Crawler API

伪代码:(不懂怎么用的Crawler API可以看scrapy自定义命令)

for i in range(指定数量):
    crawler_process.crawl(pending.pop())
crawler_process.start()
while True:
    if  len(running) < 指定数量:
        多进程执行:
            crawler_process.crawl(pending.pop())
            crawler_process.start()
    else:
        time.sleep(指定时间)

因为crawler_process.start()这个语句是阻塞的,所以需要多进程来执行。也可以去掉多进程,把extension的内容改成这样:

class SpiderCountLimit:

    def __init__(self, count):
        self.spider_count = count
        self.r = redis.Redis(decode_responses=True)

    @classmethod
    def from_crawler(cls, crawler):
        count = crawler.settings.get('SPIDER_COUNT', 20)
        ext = cls(count)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
        return ext

    def spider_closed(self, spider, reason):
        self.r.srem('running', spider.name)
        self.r.sadd('finished', spider.name)

        spider = self.r.spop('pending')
        process = CrawlerProcess()
        process.crawl(spider)
        process.start() 
        
    def spider_opened(self, spider):
        self.r.sadd('running', spider.name)

不过我感觉这个方法不如多进程添加,因为上面提到process.start() 是阻塞的,也就是说spider_closed这个方法一直没有结束,这可能会带来一些无法预见的问题。

至于其他一些细节上的优化就自己思考了,比如改用进程池来管理进程等。

相关文章

  • scrapy运行定量爬虫

    假设需求 现在大概有三千个scrapy的爬虫文件,10台机器,如何合理的分配爬虫?什么,这么简单的数学题还要问,一...

  • scrapy爬虫

    运行爬虫 scrapy crawl +<爬虫名字>Scrapy的安装:pip install scrapy创建s...

  • scrapy笔记

    1 scrapy的运行原理 参考:Learning Scrapy笔记(三)- Scrapy基础Scrapy爬虫入门...

  • 如何获取指定模块下所有的类

    前言 在使用 scrapy 时,运行爬虫仅需要通过 scrapy crawl 爬虫名 就可启动我们写好的爬虫,那么...

  • Scrapy的使用

    创建一个Scrapy项目 Scrapy的项目结构 spiders:编写爬虫的目录 爬虫的编写规则 运行你的爬虫

  • scrapy入门使用及pycharm远程调试

    一·scrapy的入门使用 scrapy的安装 创建scrapy项目 创建scrapy爬虫:在项目目录下执行 运行...

  • 创建Scrapy爬虫

    首先进入python虚拟目录 创建scrapy工程 生成爬虫 运行爬虫

  • 一. Scrapy爬虫基础

    最简单的Scrapy爬虫程序: 运行命令:scrapy crawl books -o books.csv结果截图:...

  • scrapyd和scrapyd-client使用教程

    scrapyd是一个用于部署和运行scrapy爬虫的程序,它允许你通过JSONAPI来部署爬虫项目和控制爬虫运行 ...

  • scrapy运行爬虫

    爬虫运行脚本 点击链接加入群【python技术交流】:https://jq.qq.com/?_wv=1027&k=...

网友评论

      本文标题:scrapy运行定量爬虫

      本文链接:https://www.haomeiwen.com/subject/ltozohtx.html