(原创)scrapy的MemoryError

(原创)scrapy的MemoryError


背景知识

MemoryError

MemoryError是python的常见异常之一,可以通过查看python的在线文档来进行了解:

exception MemoryError
Raised when an operation runs out of memory but the situation may still be rescued (by deleting some objects). The associated value is a string indicating what kind of (internal) operation ran out of memory. Note that because of the underlying memory management architecture (C’s malloc() function), the interpreter may not always be able to completely recover from this situation; it nevertheless raises an exception so that a stack traceback can be printed, in case a run-away program was the cause.

—— [ python在线文档]

从字义上看,这个异常是因为堆上的可用内存空间不足导致的。

scrapy爬虫的内存检查

scrapy爬虫具有其独立的内存检查工具,可以利用其自带的telnet控制台来进行内存检查。

在Scrapy中,类似Requests, Response及Items的对象具有有限的生命周期: 他们被创建,使用,最后被销毁。

这些对象中,Request的生命周期应该是最长的,其会在调度队列(Scheduler queue)中一直等待,直到被处理。 更多内容请参考 架构概览 。

由于这些Scrapy对象拥有很长的生命,因此将这些对象存储在内存而没有正确释放的危险总是存在。 而这导致了所谓的”内存泄露”。

为了帮助调试内存泄露,Scrapy提供了跟踪对象引用的机制,叫做 trackref , 或者您也可以使用第三方提供的更先进内存调试库 Guppy (更多内容请查看下面)。而这都必须在 Telnet终端 中使用。

—— [ scrapy在线文档]

问题代码:

2017-07-12 12:26:06 [scrapy.extensions.logstats] INFO: Crawled 1412 pages (at 0 pages/min), scraped 651 items (at 0 items/min)
Unhandled Error
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 440, in _finished
    self.finisher(rest)
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 954, in dispatcher
    return func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 1537, in _finishResponse_WAITING
    self._disconnectParser(reason)
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 1563, in _disconnectParser
    parser.connectionLost(reason)
--- <exception caught here> ---
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 550, in connectionLost
    self.response._bodyDataFinished()
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 954, in dispatcher
    return func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/twisted/web/_newclient.py", line 1210, in _bodyDataFinished_CONNECTED
    self._bodyProtocol.connectionLost(reason)
  File "/usr/local/lib/python2.7/dist-packages/scrapy/core/downloader/handlers/http11.py", line 406, in connectionLost
    body = self._bodybuf.getvalue()
exceptions.MemoryError: 

爬虫程序运行一段时间之后,几乎所有的request在处理过程中都出现了这样的问题。

使用telnet进行检查:

虽然scrapy的爬取过程暂时停止了,但是其程序本身仍然在运行,这是可以使用telnet终端进行检查

>telnet localhost 6023 #也可能是6023~6027中的某个值,根据设置而定。
>prefs()

Live References

CommitItem                        162   oldest: 6183s ago
GitlabSpider                        1   oldest: 44287s ago
HtmlResponse                       1923   oldest: 39205s ago
PjItem                            177   oldest: 44255s ago
Request                           2023   oldest: 44260s ago
Selector                           228   oldest: 39210s ago

这里可以看到当前运行过程中堆上内存的所有对象。

代码修改

 确定是内存中的并发请求过多导致的问题,这里我首先想到了这个办法:
(1)对生成request的方法进行改造,让其每次生成一部分request之后暂停生成,但是无法确定每次生成的request何时可以运行完毕。
(2)目前的爬虫带宽实际上也无法支持多达32个爬取线程,现在对爬取线程进行数目限制,让并发的请求最多只做8个,这样速度也没有明显的下降,而内存中的待处理HTTP请求对象数目也可以维持在300到500个左右。不会导致内存泄露。
Live References

CommitItem                        123   oldest: 1073s ago
GitlabSpider                        1   oldest: 4883s ago
HtmlResponse                       52   oldest: 847s ago
PjItem                            177   oldest: 4881s ago
Request                           360   oldest: 4881s ago
Selector                           51   oldest: 847s ago

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值