Scrapy中的记忆泄漏

Rob*_*bin 5 python scrapy web-scraping

我编写了以下代码来搜索电子邮件地址(用于测试目的):

import scrapy
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.selector import Selector
from crawler.items import EmailItem

class LinkExtractorSpider(CrawlSpider):
    name = 'emailextractor'
    start_urls = ['http://news.google.com']

    rules = ( Rule (LinkExtractor(), callback='process_item', follow=True),)

    def process_item(self, response):
        refer = response.url
        items = list()
        for email in Selector(response).re("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}"):

            emailitem = EmailItem()
            emailitem['email'] = email
            emailitem['refer'] = refer
            items.append(emailitem)
        return items
Run Code Online (Sandbox Code Playgroud)

不幸的是,似乎没有正确关闭对请求的引用,就像scrapy telnet控制台一样,请求数量增加了5k/s.在约3分钟和10k刮页后,我的系统开始交换(8GB RAM).任何人都知道出了什么问题?我已经尝试删除引用并使用"复制"字符串

emailitem['email'] = ''.join(email)
Run Code Online (Sandbox Code Playgroud)

没有成功.在抓取之后,这些项目将被保存到BerkeleyDB中,计算它们的出现次数(使用管道),因此之后的引用应该消失.

返回一组物品和分别产生每件物品有什么区别?

编辑:

经过一段时间的调试,我发现,请求没有被释放,这样我最终得到:

$> nc localhost 6023
>>> prefs()
Live References
Request 10344   oldest: 536s ago
>>> from scrapy.utils.trackref import get_oldest
>>> r = get_oldest('Request')
>>> r.url
<GET http://news.google.com>
Run Code Online (Sandbox Code Playgroud)

这实际上是起始网址.谁知道问题是什么?缺少对Request对象的引用在哪里?

EDIT2:

在服务器(具有64GB RAM)上运行约12小时后,使用的RAM约为16GB(使用ps,即使ps不是正确的工具).问题是,抓取的页面数量大幅下降,并且已抓取的项目数量从小时开始保持为0:

INFO: Crawled 122902 pages (at 82 pages/min), scraped 3354 items (at 0 items/min)
Run Code Online (Sandbox Code Playgroud)

EDIT3:我做了objgraph分析,结果如下图(感谢@Artur Gaspar): Python Objgraph Backlink

我似乎不能影响它?

Rob*_*bin 8

对我来说,最后的答案是将基于磁盘的队列与工作目录结合使用作为运行时参数.

这是将以下代码添加到settings.py:

DEPTH_PRIORITY = 1 
SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'
Run Code Online (Sandbox Code Playgroud)

之后,使用以下命令行启动爬网程序会使更改在给定目录中持久化:

scrapy crawl {spidername} -s JOBDIR = crawls/{spidername} 有关详细信息,请参阅scrapy docs

这种方法的附加好处是,可以随时暂停和恢复爬网.我的蜘蛛现在运行超过11天,阻止~15GB内存(磁盘FIFO队列的文件缓存)


小智 5

我想指出罗宾斯答案的更新(还不能在他的帖子中回复,低代表)。

确保您对队列使用新的语法因为它们的建议现在已被弃用。这个“s”花了我几天的时间才弄清楚出了什么问题。新的语法是这样的:

    DEPTH_PRIORITY = 1 
    SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
    SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
Run Code Online (Sandbox Code Playgroud)