scrapy 下载图片到 4w 张左右总是会卡住

2017-06-03 11:30:10 +08:00
 Yingruoyuan

已经从本地直接获取图片 url,大概有 20w 个左右,在下载到 4w 左右 scrapy 总是卡住,开始以为是内存泄漏,后来检测内存和 cpu 使用率,在卡住的时候并没有发现异常,下载部分代码如下:

def parse(self, response):
    //get local list_img_urls
    item = DownloaderItem()
    item['image_urls'] = list_img_urls
    yield item

有人遇到过这种情况吗?望不吝相助

4242 次点击
所在节点    Python
15 条回复
yangxin0
2017-06-03 12:43:55 +08:00
scrapy 的设计是 spider 是去爬取 HTML 页面的,然后转换成 Item, 然后通过 pipeline 去下载 item 关联的照片。 我每天下载 150 万张照片无压力。
Yc1992
2017-06-03 12:50:03 +08:00
去重的部分在内存里,太多就会缓存到磁盘,那就慢了
ooh
2017-06-03 12:52:00 +08:00
图片下载应该是 ImagesPipeline ?
rabbbit
2017-06-03 13:26:30 +08:00
DOWNLOAD_TIMEOUT 和 CONCURRENT_REQUESTS 怎么设置的,
是不是无响应的链接超过并发数限制了?
imn1
2017-06-03 13:33:53 +08:00
抓到两个集图的
Yingruoyuan
2017-06-03 19:49:03 +08:00
@Yc1992 我是在空目录下重新下载的,img_url 里一般也不会有重复的

@ooh 是的,是用的继承 ImagesPipeline 的方法
@rabbbit DOWNLOAD_TIMEOUT = 30,CONCURRENT_REQUESTS 这个用的默认的,应该是 8 个吧
Yingruoyuan
2017-06-03 20:38:10 +08:00
@rabbbit 刚才是我看错了,CONCURRENT_REQUESTS 默认的是 16 个,我尝试了把 RETRY_ENABLED = False,并且缩短了 download_timeout,但是并没有明显改善,但是我发现虽然 top 监控的内存占用率并没有提高,但是在卡住的那段时间里,输入命令等会变得很卡,我在找是不是和服务器性能哪里有关的原因导致的
litter123
2017-06-03 20:59:48 +08:00
@Yingruoyuan 查看连接数,netstat -an
Yc1992
2017-06-03 22:11:40 +08:00
@Yingruoyuan scrapy 为了去重,会把 url 缓存在内存中,超过一定数量,就只能写磁盘了,那时候 io 超高就卡死了,这是我遇到过的情况。
Yingruoyuan
2017-06-04 15:29:50 +08:00
@litter123 我对 netstat 命令不大熟悉,可以给个提示应该怎么查看 scrapy 的异常连接吗?
@Yc1992 哦,这种情况,我以前没有遇到过,请教下这种情况是怎么去 debug 呢?
Yc1992
2017-06-04 16:50:58 +08:00
@Yingruoyuan 看 io,看内存占用
zsz
2017-06-04 18:06:42 +08:00
@Yingruoyuan

仔细检查进程资源占用情况

top: 看 cpu,内存
iotop,iostat:看磁盘 io 情况
nmon:看系统网络资源情况
nload:看网卡流量情况
ss,netstat:看网络连接


加我们的群问效率高些,一群工程师组建的面向初学者的
Python Linux 学习群,qq 群号:278529278,
Php Linux 学习群,qq 群号:476648701,
非商业性质,拒绝广告,只接收真正想学这方面技术的朋友,交流学习,申请请说明来自 v2ex
Yingruoyuan
2017-06-04 21:49:44 +08:00
@Yc1992 好的,谢谢,我去检查下 io
@zsz 谢谢
Yingruoyuan
2017-06-05 16:05:47 +08:00
@all,
感谢各位提供帮助,问题应该还是出在内存上,由于我是可以直接拿到那几十万的 url 的,这些请求会进入到在 scrapy 的请求队列中,占用内存,直至最后服务器内存不够 down 掉;
我在网上查了下资料,scrapy 的调度器来控制队列,但是似乎不 hack 源码没有办法控制调度器对队列的操作;
最后我的解决方法是在数据库就把数据切片,切成 2w 套循环,就不会出现内存不够的问题了;
希望后来的大神有更优雅的方法可以指教。我会持续关注这个问题
noobpythoner
2017-06-08 12:52:23 +08:00
可以使用 scrapy_redis 来完成,所有的去重都是通过 redis 来完成的,还能够做到状态保持,如果需要可以实现分布式,redis 的内容类似下面,
redis > keys *
1) "***:dupefilter"
2) "***:items"
3) "***:requests"

或者可以迭代的读取数据库的内容,下一次请求之前从内存中删除上一次的请求地址,类似 https://www.ibm.com/developerworks/cn/xml/x-hiperfparse/
这个方法我自己没有试过,但是应该是可行的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/365631

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX