2016-05-02 3 views
17

У меня проблема. Мне нужно некоторое время прекратить выполнение функции, но не останавливать реализацию синтаксического анализа в целом. То есть мне нужна неблокирующая пауза.Scrapy: неблокирующая пауза

Это выглядит следующим образом: должна быть остановлена ​​на некоторое время

class ScrapySpider(Spider): 
    name = 'live_function' 

    def start_requests(self): 
     yield Request('some url', callback=self.non_stop_function) 

    def non_stop_function(self, response): 
     for url in ['url1', 'url2', 'url3', 'more urls']: 
      yield Request(url, callback=self.second_parse_function) 

     # Here I need some function for sleep only this function like time.sleep(10) 

     yield Request('some url', callback=self.non_stop_function) # Call itself 

    def second_parse_function(self, response): 
     pass 

Функция non_stop_function, но он не должен блокировать остальную часть вывода.

Если я вставляю time.sleep() - он остановит весь синтаксический анализатор, но мне это не нужно. Можно ли остановить одну функцию, используя twisted или что-то еще?

Причина:: Мне нужно создать неблокирующую функцию, которая будет анализировать страницу сайта каждые n секунд. Там она получит URL-адреса и заполнит 10 секунд. Полученные URL-адреса будут продолжать работать, но основная функция должна спать.

UPDATE:

Благодаря TkTech и Вяч. Один из ответов помог мне понять, как сделать ожидающий Request, а второй - как его активировать. Оба ответа дополняет друг друг, и я сделал отличную нелипкую паузу Scrapy:

def call_after_pause(self, response): 
    d = Deferred() 
    reactor.callLater(10.0, d.callback, Request(
     'https://example.com/', 
     callback=self.non_stop_function, 
     dont_filter=True)) 
    return d 

И использовать эту функцию для моего запроса:

yield Request('https://example.com/', callback=self.call_after_pause, dont_filter=True) 
+0

Может ли этот подход помочь? http://stackoverflow.com/questions/37002742/calling-the-same-spider-programmatic/37007619#37007619 –

+0

@ RafaelAlmeida Это не очень удобный способ. Я хочу использовать эту паузу в будущем, не ставя под угрозу архитектуру анализатора. – JRazor

+0

Вы хотите приостановить его, чтобы не сделать запрос? или просто сделать паузу внутри метода? было бы очень полезно, если бы вы могли указать причину этой паузы. – eLRuLL

ответ

6

Request объект имеет callback параметр, попробуйте использовать этот один для этой цели. Я имею в виду, создайте Deferred, который обертывает self.second_parse_function и pause.

Вот мой грязный и не проверенный пример, отмечены измененные строки.

class ScrapySpider(Spider): 
    name = 'live_function' 

    def start_requests(self): 
     yield Request('some url', callback=self.non_stop_function) 

    def non_stop_function(self, response): 

     parse_and_pause = Deferred() # changed 
     parse_and_pause.addCallback(self.second_parse_function) # changed 
     parse_and_pause.addCallback(pause, seconds=10) # changed 

     for url in ['url1', 'url2', 'url3', 'more urls']: 
      yield Request(url, callback=parse_and_pause) # changed 

     yield Request('some url', callback=self.non_stop_function) # Call itself 

    def second_parse_function(self, response): 
     pass 

Если подход работает для вас, то вы можете создать функцию, которая строит Deferred объекта в соответствии с правилом. Это может быть реализовано в пути, как в следующем:

def get_perform_and_pause_deferred(seconds, fn, *args, **kwargs): 
    d = Deferred() 
    d.addCallback(fn, *args, **kwargs) 
    d.addCallback(pause, seconds=seconds) 
    return d 

И здесь возможно использование:

class ScrapySpider(Spider): 
    name = 'live_function' 

    def start_requests(self): 
     yield Request('some url', callback=self.non_stop_function) 

    def non_stop_function(self, response): 
     for url in ['url1', 'url2', 'url3', 'more urls']: 
      # changed 
      yield Request(url, callback=get_perform_and_pause_deferred(10, self.second_parse_function)) 

     yield Request('some url', callback=self.non_stop_function) # Call itself 

    def second_parse_function(self, response): 
     pass 
5

Если вы пытаетесь использовать это для ограничения скорости , вы, вероятно, просто хотите использовать DOWNLOAD_DELAY.

Scrapy - это всего лишь каркас на вершине Twisted. По большей части, вы можете относиться к нему так же, как и к любому другому скрученному приложению. Вместо того, чтобы вызывать сон, просто верните следующий запрос, чтобы сделать и сказать, что скрученный должен немного подождать. Пример:

from twisted.internet import reactor, defer 

def non_stop_function(self, response) 
    d = defer.Deferred() 
    reactor.callLater(10.0, d.callback, Request(
     'some url', 
     callback=self.non_stop_function 
    )) 
    return d 
+0

Python не может использовать не пустые 'return' и' yield' для одной функции. Я знаю о 'download_delay', но это не моя ситуация. – JRazor

+1

@JRazor Просто структурируйте свой метод лучше. – TkTech

+0

попытайтесь использовать 'return' со значением и' yield' для одной функции. – JRazor

0

автор вопроса уже дает ответ на обновление на вопрос, но я хочу дать немного лучше чтобы он был повторно использован для любого запроса.

# removed... 
from twisted.internet import reactor, defer 

class MySpider(scrapy.Spider): 
    # removed... 

    def request_with_pause(self, response): 
     d = defer.Deferred() 
     reactor.callLater(response.meta['time'], d.callback, scrapy.Request(
      response.url, 
      callback=response.meta['callback'], 
      dont_filter=True, meta={'dont_proxy':response.meta['dont_proxy']})) 
     return d 

    def parse(self, response): 
     # removed.... 
     yield scrapy.Request(the_url, meta={ 
          'time': 86400, 
          'callback': self.the_parse, 
          'dont_proxy': True 
          }, callback=self.request_with_pause) 

Для объяснения Scrapy использовать Twisted управлять запросом асинхронно, так что нам нужен инструмент витого, чтобы сделать замедленный запрос тоже.

+0

Я получаю это сообщение об ошибке'ERROR: Паук должен вернуть Request, BaseItem, dict или None, получив «Отложенный» при попытке этого метода. Возможно, произошли изменения в последних версиях? –