2016-05-02 18 views
17

Ho un problema. Devo interrompere l'esecuzione di una funzione per un po ', ma non interrompere l'implementazione del parsing nel suo complesso. Cioè, ho bisogno di una pausa non bloccante.Scrapy: pausa non bloccante

E 'assomiglia:

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 

Funzione non_stop_function deve essere fermato per un po', ma non dovrebbe bloccare il resto della produzione.

Se inserisco time.sleep() - interromperà l'intero parser, ma non ne ho bisogno. È possibile interrompere una funzione utilizzando twisted o qualcos'altro?

Motivo: È necessario creare una funzione non bloccante che analizzerà la pagina del sito Web ogni n secondi. Lì riceverà url e riempirà per 10 secondi. Gli URL che sono stati ottenuti continueranno a funzionare, ma la funzionalità principale deve essere interrotta.

UPDATE:

Grazie a TkTech e viach. Una risposta mi ha aiutato a capire come effettuare una sospensione Request, e la seconda è come attivarla. Entrambe le risposte si completano a vicenda e io abbiamo fatto un ottimo pausa non-blocking per 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 

E utilizzare questa funzione per la mia richiesta:

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

Questo approccio può aiutare? http://stackoverflow.com/questions/37002742/calling-the-same-spider-programmatically/37007619#37007619 –

+0

@RafaelAlmeida Non è un modo molto conveniente. Voglio usare questa pausa in futuro senza compromettere l'architettura del parser. – JRazor

+0

vuoi metterlo in pausa per non fare una richiesta? o semplicemente mettere in pausa all'interno del metodo? sarebbe molto utile se potessi specificare una ragione di questa pausa. – eLRuLL

risposta

6

Request oggetto ha callback parametro, tenta di utilizzare quella per lo scopo. Intendo, creare un Deferred che include self.second_parse_function e pause.

Ecco il mio esempio sporco e non testato, le linee modificate sono contrassegnate.

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 

Se l'approccio funziona per voi quindi è possibile creare una funzione che costruisce un oggetto Deferred secondo la regola. Si potrebbe essere implementato in modo simile alla seguente:

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

E qui è possibile uso:

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

Se si sta tentando di utilizzare questo per rate limiting , probabilmente vuoi semplicemente usare DOWNLOAD_DELAY invece.

Scrapy è solo una struttura in cima a Twisted. Per la maggior parte, puoi trattarlo come qualsiasi altra applicazione ritorta. Invece di chiamare il sonno, basta restituire la richiesta successiva per fare in modo che torni ad aspettare un po '. Es:

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 non può usare non restituire 'return' e' yield' per una funzione. Conosco 'download_delay', ma non è la mia situazione. – JRazor

+1

@JRazor Semplicemente strutturate meglio il vostro metodo. – TkTech

+0

prova a usare 'return' con valore e' yield' per una funzione. – JRazor

0

Il richiedente fornisce già una risposta in aggiornamento della domanda, ma voglio dare un po 'meglio versione quindi è riutilizzabile per qualsiasi richiesta.

# 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) 

Per una spiegazione, Scrapy utilizzare ritorto per gestire la richiesta in modo asincrono, quindi abbiamo bisogno di attrezzi in torto di fare una richiesta in ritardo troppo.

+0

Ricevo questo messaggio di errore'ERROR: Spider deve restituire Request, BaseItem, dict o None, ha 'Deferred'' quando si prova questo metodo. C'è stato forse un cambiamento nelle versioni recenti? –