当前位置: 首页 > 后端技术 > Python

scrapy自定义扩展(extensions)实现实时监控scrapy爬虫的运行状态

时间:2023-03-26 17:08:24 Python

Scrapy自定义扩展(扩展)实现实时监控scrapy爬虫运行状态呢?官方其实提供了一个字典,里面包含了一些爬虫的相关信息:crawler.stats.get_stats(),爬虫是scrapy中的一个组件。您可以在许多组件中访问它,例如所有包含from_crawler(cls,crawler)方法的组件。既然可以获取到scrapy的运行状态,那么实时显示应该很容易。同样使用上一篇博客中使用的influxdb+grafana来展示数据。我们只需要将scrapy的一些运行信息实时同步到influxdb数据库,就可以通过grafana以图表的形式展示数据库的内容了。数据库怎么写实时同步字典到数据库?这里必须设置一个同步时间间隔,假设是5秒。那么我们的需求就是让scrapy每5秒将爬虫运行状态的信息写入数据库中。上面说到,可以访问crawler.stats.get_stats()的组件有很多,比如中间件、管道、爬虫等。我们应该在哪个组件中同步信息?为此,我们可以先看一些内置组件实现的功能,再看与需求最相近的功能。显然,最合适的功能是扩展组件。很多人可能没有用过这个组件。我看很多博客很少提到这个组件,因为这个组件能做什么,其他人也能做什么,用它只是为了让分工更明确。因此,一般会在extensions中写入一些额外的功能。我们来看看内置的都实现了哪些功能。Logstatisticsextension(scrapy.extensions.logstats.LogStats):记录基本的统计信息,例如爬取的页面和ScrapeditemsCoreStatsExtension(scrapy.extensions.corestats.CoreStats):如果启用了统计收集,则启用核心统计收集TelnetConsoleExtension(scrapy.extensions.telnet.TelnetConsole):提供一个telnet控制台,进入当前运行的Scrapy进程中的Python解释器,对调试内存使用很有用logstatisticsextension所在的windows将crawler.stats.get_stats()的字典信息写入log中,和我要实现的功能基本类似。所以代码可以参考参考。直接看我的代码:importloggingfromscrapyimportsignalsimportdatetimefromthreadingimportTimerfrominfluxdbimportInfluxDBClientlogger=logging.getLogger(__name__)classSpiderStatLogging:def__init__(self,crawler,dbparams,interval):self.exit_code=Falseself.interval=intervalself.crawler=爬虫self.client=InfluxDBClient(**dbparams)self.stats_keys=set()self.cur_d={'log_info':0,'log_warning':0,'requested':0,'request_bytes':0,'response':0,'response_bytes':0,'response_200':0,'response_301':0,'response_404':0,'responsed':0,'item':0,'filtered':0,}@classmethoddeffrom_crawler(cls,crawler):dbparams=crawler.settings.get('INFLUXDB_PARAMS')interval=crawler.settings.get('INTERVAL',60)ext=cls(crawler,dbparams,间隔)crawler.signals.connect(ext.engine_started,signal=signals.engine_started)crawler.signals.connect(ext.engine_stopped,signal=signals.engine_stopped)crawler.signals.connect(ext.spider_closed,signal=signals.spider_closed)crawler.signals.connect(ext.spider_opened,signal=signals.spider_opened)returnextdefspider_closed(self,spider,reason):logger.info(self.stats_keys)influxdb_d={“测量”:“spider_closed”,"time":datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ'),"tags":{'spider_name':spider.name},"fields":{'end_time':datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S'),'reason':原因,'spider_name':spider.名称}}如果不是self.client.write_points([influxdb_d]):raiseException('写入influxdb失败!')defspider_opened(self,spider):influxdb_d={"measurement":"spider_opened","time":datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ'),"tags":{'spider_name':spider.name},"fields":{'start_time':datetime.datetime.now().strftime('%Y-%m-%d%H:%M:%S'),'spider_name':spider.name}}ifnotself.client.write_points([influxdb_d]):raiseException('写入influxdb失败!')defengine_started(self):定时器(self.interval,self.handle_stat).start()defengine_stopped(self):self.exit_code=Truedefhandle_stat(self):stats=self.crawler.stats.get_stats()d={'log_info':stats.get('log_count/INFO',0),'dequeued':stats.get('scheduler/dequeued/redis',0),'log_warning':stats.get('log_count/WARNING',0),'requested':stats.get('downloader/request_count',0),'request_bytes':stats.get('downloader/request_bytes',0),'response':stats.get('downloader/response_count',0),'response_bytes':stats.get('downloader/response_bytes',0),'response_200':stats.get('downloader/response_status_count/200',0),'response_301':stats.get('downloader/response_status_count/301',0),'response_404':stats.get('downloader/response_status_count/404',0),'responsed':stats.get('response_received_count',0),'item':stats.get('item_scraped_count',0),'depth':stats.get('request_depth_max',0),'filtered':stats.get('bloomfilter/filtered',0),'enqueued':stats.get('scheduler/enqueued/redis',0),'spider_name':self.crawler.spider.name}forkeyinself.cur_d:d[key],self.cur_d[key]=d[key]-self.cur_d[key],d[key]influxdb_d={“测量”:“newspider”,“时间”:datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ'),"tags":{'spider_name':self.crawler.spider.name},"fields":d}如果不是自己.client.write_points([influxdb_d]):raiseException('Failedtowritetoinfluxdb!')self.stats_keys.update(stats.keys())如果不是self.exit_code:Timer(self.interval,self.handle_stat).start()代码应该不难理解。从settings.py中读取'INFLUXDB_PARAMS'和'INTERVAL'两个变量,然后在引擎启动时启动一个定时器,每隔INTERVAL秒执行一次handle_stat函数。handle_stat函数作用是将crawler.stats.get_stats()字典写入influxdb数据库,然后只需要在配置文件中开启这个扩展即可,EXTENSIONS={'项目名称。Filename.SpiderStatLogging':1,#假设上面的代码存放在extensions.py中,和settings.py放在同级目录下,#可以写成:项目名.extensions..SpiderStatLogging}displaydatabasegranfanaI就不多说了,不懂的请自行百度,或者看看我上一篇博客再百度。Chartjson:https://lanzous.com/icrr5kb(...,复制到grafana导入即可)