Scrapy 内存错误(请求过多)Python 2.7

Scrapy Memory Error (too many requests) Python 2.7

我一直是 运行 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 似乎喜欢留下来 "shallow," 累积请求在内存中等待,而不是深入研究它们然后备份。

结果是一个重复的大异常,结束如下:

  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 出队、外部化或迭代(我什至不知道正确的词)存储的请求以防止这样的内存问题?

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

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

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

您可以通过每次蜘蛛空闲时只排队几个来批量处理您的网址。这避免了有很多请求在内存中排队。下面的示例仅从您的 database/file 读取下一批 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