2016-05-02 27 views
17

問題があります。私はしばらくの間、関数の実行を停止する必要がありますが、全体として解析の実装を停止する必要はありません。つまり、私は非ブロッキングの一時停止が必要です。治療:ノンブロッキング・ポーズ

イッツのようになります。

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などを使用して1つの機能を停止することはできますか?

理由::n秒ごとにウェブサイトのページを解析する非ブロック機能を作成する必要があります。そこに彼女はURLを取得し、10秒間満たします。取得されたURLは引き続き機能しますが、主な機能はスリープ状態にある必要があります。

UPDATETkTechviach

感謝。 1つの答えは私が保留中のRequestを作成する方法を理解する助けとなり、2番目の方法はそれをアクティブにする方法です。どちらの答えはお互いを補完し、私はScrapyための優れたノン・ブロッキングのポーズ製:あなたはレート制限のためにこれを使用しようとしている場合

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

このアプローチは役に立ちますか? http://stackoverflow.com/questions/37002742/calling-the-same-spider-programmatically/37007619#37007619 –

+0

@RafaelAlmeida非常に便利な方法ではありません。私は、パーサのアーキテクチャを妥協することなく、このポーズを将来使用したいと思っています。 – JRazor

+0

リクエストをしないように一時停止しますか?メソッド内で一時停止しますか?この一時停止の理由を指定できると非常に役に立ちます。 – eLRuLL

答えて

6

Requestオブジェクトがcallbackパラメータがあり、目的のための1つを使用するようにしてください。 self.second_parse_functionpauseをラップするDeferredを作成します。

ここでは私の汚れていてテストされていない例です。変更された行がマークされています。

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オブジェクトを構築する関数を作成することができます。アスカーはすでに問題のアップデートで答えを提供していますが、私はわずかに良いを与えたい

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

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 

そして、私の要求のためにこの機能を使用しますおそらく代わりにDOWNLOAD_DELAYを使用したいだけです。

スクリーニングは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は1つの関数に対して空の 'return'と' yield'を使うことはできません。私は 'download_delay'について知っているが、それは私の状況ではない。 – JRazor

+1

@JRazorメソッドを簡単に構造化するだけです。 – TkTech

+0

1つの関数に対して 'return'をvalueと' yield'で使用しようとします。 – JRazor

0

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

そして、ここでは可能である用法:それは、次のような方法で実施することができますそれはどんなリクエストでも再利用可能です。説明のために

# 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は、非同期要求を管理するためにツイストを使用するので、私たちはあまりにも遅れて、要求を行うためのツイストのツールが必要です。

+0

このエラーメッセージ'ERRORが発生しました:このメソッドを試しているときにSpiderがRequest、BaseItem、dictまたはNoneを返さなければなりません。最近のバージョンに変更があった可能性はありますか? –