【问题标题】:Scrapy Memory Error (too many requests) Python 2.7Scrapy 内存错误(请求过多)Python 2.7
【发布时间】:2015-09-01 21:25:38
【问题描述】:

我一直在 Scrapy 中运行一个爬虫来爬取一个我不想提及的大型网站。我使用教程蜘蛛作为模板,然后我创建了一系列启动请求并让它从那里爬取,使用如下内容:

def start_requests(self):
        f = open('zipcodes.csv', 'r')
        lines = f.readlines()
        for line in lines:
            zipcode = int(line)
            yield self.make_requests_from_url("http://www.example.com/directory/%05d" % zipcode)

首先,有超过 10,000 个这样的页面,然后每个页面都在一个相当大的目录中排队,从中还有几个页面要排队,等等,scrapy 似乎喜欢保持“浅层”,累积请求在内存中等待,而不是深入研究它们然后备份。

这样做的结果是一个重复的大异常,以这样的方式结束:

  File "C:\Python27\lib\site-packages\scrapy\utils\defer.py", line 57, in <genexpr>
    work = (callable(elem, *args, **named) for elem in iterable)
--- <exception caught here> ---
  File "C:\Python27\lib\site-packages\scrapy\utils\defer.py", line 96, in iter_errback
    yield next(it)

.....(更多行).....

  File "C:\Python27\lib\site-packages\scrapy\selector\lxmldocument.py", line 13, in _factory
    body = response.body_as_unicode().strip().encode('utf8') or '<html/>'
exceptions.MemoryError: 

很快,在一个需要几天时间的爬虫程序的一个小时左右内,python 可执行文件就会膨胀到 1.8gigs 并且 Scrapy 将不再起作用(继续花费我很多浪费的美元代理使用费!)。

有什么方法可以让 Scrapy 出列、外部化或迭代(我什至不知道正确的词)存储的请求以防止此类内存问题?

(我对编程不是很精通,除了拼凑我在这里或文档中看到的内容,所以我没有能力在引擎盖下进行故障排除,可以这么说 - 我也无法安装经过几天的尝试和阅读,完整的 python/django/scrapy 在 W7 上为 64 位。)

【问题讨论】:

  • 不要将 CONCURRENT_ITEMS 设置设置得太高。我将它设置为 60.000,我也得到了 MemoryError。您是否添加了任何并发设置?

标签: python django python-2.7 memory scrapy


【解决方案1】:

在整个 Internet 上递归链接时,您将无法关闭。您将需要以一种或另一种方式限制递归。不幸的是,没有显示您要执行此操作的代码部分。最简单的方法是为待抓取的待抓取链接列表设置一个固定大小,并且在它小于此上限之前不再向列表中添加任何内容。更高级的解决方案将根据父页面中的周围上下文为待处理链接分配优先级,然后将排序添加到待处理链接的已排序、固定最大大小的优先级列表中。

但是,与其尝试编辑或破解现有代码,不如看看内置设置是否可以实现您想要的。请参阅此文档页面以供参考:http://doc.scrapy.org/en/latest/topics/settings.html。看起来DEPTH_LIMIT 的值设置为 1 或更大会限制您从起始页开始的递归深度。

【讨论】:

  • 我认为这种方法可能有害而不是有益。父响应对象可能大于它将生成的所有请求对象。保持响应打开内存以限制来自它的请求会导致更多的内存使用。
【解决方案2】:

您可以通过每次蜘蛛空闲时只排队几个来批量处理您的网址。这样可以避免大量请求在内存中排队。下面的示例仅从您的数据库/文件中读取下一批 url,并仅在完成所有先前的请求处理后将它们作为请求排队。

有关spider_idle 信号的更多信息:http://doc.scrapy.org/en/latest/topics/signals.html#spider-idle

有关调试内存泄漏的更多信息:http://doc.scrapy.org/en/latest/topics/leaks.html

from scrapy import signals, Spider
from scrapy.xlib.pydispatch import dispatcher


class ExampleSpider(Spider):
    name = "example"
    start_urls = ['http://www.example.com/']

    def __init__(self, *args, **kwargs):
        super(ExampleSpider, self).__init__(*args, **kwargs)
        # connect the function to the spider_idle signal
        dispatcher.connect(self.queue_more_requests, signals.spider_idle)

    def queue_more_requests(self, spider):
        # this function will run everytime the spider is done processing
        # all requests/items (i.e. idle)

        # get the next urls from your database/file
        urls = self.get_urls_from_somewhere()

        # if there are no longer urls to be processed, do nothing and the
        # the spider will now finally close
        if not urls:
            return

        # iterate through the urls, create a request, then send them back to
        # the crawler, this will get the spider out of its idle state
        for url in urls:
            req = self.make_requests_from_url(url)
            self.crawler.engine.crawl(req, spider)

    def parse(self, response):
        pass

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    相关资源
    最近更新 更多