2015-06-16 2 views
1

Я запускал искатель в Scrapy для сканирования большого сайта, о котором я бы не упомянул. Я использую учебник паука в качестве шаблона, а затем я создал серию стартовых запросов и пусть ползают оттуда, используя что-то вроде этого:Ошибка памяти Scrapy (слишком много запросов) Python 2.7

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 как 64-бит на W7, после нескольких дней попыток и чтения.)

+1

Не устанавливайте параметры CONCURRENT_ITEMS слишком высоко. Я установил его на 60 000, и я тоже получил MemoryError. Вы добавляли какие-либо настройки при параллелизме? –

ответ

1

Вы можете обрабатывать свои URL-адреса с помощью пакета, только в очередях в очереди каждый раз, когда паук простаивает. Это позволяет избежать большого количества запросов, стоящих в очереди в памяти. Приведенный ниже пример только считывает следующую партию 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 
1

Вы не сможете достичь закрытия при рекурсивных ссылках по всему Интернету. Вам нужно будет ограничить рекурсию тем или иным способом. К сожалению, часть кода, где вы это сделаете, не отображается. Самый простой способ - установить фиксированный размер в список ожидающих ссылок для обхода и просто не добавлять больше в список, пока он не станет меньше этой кепки. Более продвинутые решения будут назначать приоритет ожидающим ссылкам на основе их окружающего контекста на родительской странице, а затем сортировать добавляет к отсортированному списку приоритетов с фиксированным максимальным размером ожидающих ссылок.

Вместо того чтобы пытаться отредактировать или взломать существующий код, вы должны увидеть, могут ли встроенные настройки выполнить то, что вы хотите. См. Эту страницу документа для справки: http://doc.scrapy.org/en/latest/topics/settings.html. Похоже, что настройка DEPTH_LIMIT со значением 1 или более ограничит глубину рекурсии от начальных страниц.

+0

Я думаю, что этот подход может быть вредным, а не полезным. Объекты родительского ответа, вероятно, больше, чем все объекты запроса, которые он будет генерировать.Сохранение ответной памяти для ограничения запросов от нее приведет к большему использованию памяти. – Rejected

Смежные вопросы