背景
在使用scrapy爬取东西的时候,使用crontab定时的启动爬虫,但是发现机器上经常产生很多卡死的scrapy进程,一段时间不管的话,会导致有10几个进程都卡死在那,并且会导致数据产出延迟。
问题定位
使用py-spy这个非常好用的python性能分析工具来进行排查,py-spy可以查看一个python进程函数调用用时,类似unix下的top命令。所以我们用这个工具看看是什么函数一直在执行。
首先安装这个工具
pip install py-spy
用py-spy看看scrapy哪个函数执行时间长
# 先找到这个卡死的scrapy进程的pid ps -ef |grep scrapy # 启动 py-spy 观察这进程 py-spy top --pid 53424
首先我们按3,按OwnTime进行排序,这个表示函数自身执行的时间,可以看到read这个函数执行的时间最长,那看来是IO导致的,程序中的IO行为就是读写磁盘和网络IO,磁盘读写一般不会有问题,所以初步定位是网络IO导致的。
接下来进行进一步确认,再按4,按TotalTIme 所有子函数执行时间总和进行排序,可以看到是在process_item和download,upload_image这些主流程函数的执行时间比较长,这一步是先把图片下载到本地,然后上传到静床,看来是下载这步从网络中read数据时出现了问题,进一步追踪代码。
看下download的函数的代码:
if filename == '': filename = os.path.basename(url) path = path + '/' + filename try: res = request.urlretrieve(url,filename=path) print(url,res) return path except Exception as e: print('download img failed') print(e) return False
可以看到用了urllib这个库里面request.urlretrieve函数,这个函数是用来下载文件的,去看看python官网文档的函数说明,发现里面没有超时时间这个参数,所以是由于没有超时时间,导致一直在read,进而使得进程卡死。
urllib.request.urlretrieve(url, filename=None,reporthook=None,data=None)
解决方案
使用另一种方式来下载图片,使用支持超时时间的urlopen函数,封装成一个自定义的url_retrieve,这样就不再会出现没有超时导致的卡死问题了。
def url_retrieve(self,url, path): r = request.urlopen(url, timeout=5) res = False with open(path,"wb") as f: res = f.write(r.read()) f.flush() f.close() return res
到此这篇关于使用py-spy解决scrapy卡死的问题方法的文章就介绍到这了,更多相关scrapy卡死内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!