2017-10-11 5 views
2

Ich möchte wiederholt die gleichen URLs mit verschiedenen Verzögerungen kratzen. Nach der Untersuchung des Problems schien es, dass die richtige Lösung darin bestand, etwas zu verwenden, wie etwas.Verzögerte Anfragen in scrapy

Allerdings konnte ich diese Arbeit nicht machen. Ich erhalte die Fehlermeldung ERROR: Spider must return Request, BaseItem, dict or None, got 'Deferred'

ich mit verdrehtem nicht vertraut bin so hoffe ich bin nur etwas offensichtlich

fehle

Gibt es einen besseren Weg, um mein Ziel zu erreichen, die nicht den Rahmen nicht kämpfen, so viel?

Antwort

1

fand ich endlich eine Antwort in an old PR

def parse(): 
     req = scrapy.Request(...) 
     delay = 0 
     reactor.callLater(delay, self.crawler.engine.schedule, request=req, spider=self) 

Allerdings kann die Spinne früh zu seinem Leerlauf beenden durch. Basierend auf der veralteten Middleware https://github.com/ArturGaspar/scrapy-delayed-requests, kann dies mit

from scrapy import signals 
from scrapy.exceptions import DontCloseSpider 

class ImmortalSpiderMiddleware(object): 

    @classmethod 
    def from_crawler(cls, crawler): 
     s = cls() 
     crawler.signals.connect(s.spider_idle, signal=signals.spider_idle) 
     return s 

    @classmethod 
    def spider_idle(cls, spider): 
     raise DontCloseSpider() 

Die letzte Option behoben werden, die Middleware von ArturGaspar aktualisieren, führte zu:

from weakref import WeakKeyDictionary 

from scrapy import signals 
from scrapy.exceptions import DontCloseSpider 
from twisted.internet import reactor 

class DelayedRequestsMiddleware(object): 
    requests = WeakKeyDictionary() 

    @classmethod 
    def from_crawler(cls, crawler): 
     ext = cls() 
     crawler.signals.connect(ext.spider_idle, signal=signals.spider_idle) 
     return ext 

    @classmethod 
    def spider_idle(cls, spider): 
     if cls.requests.get(spider): 
      spider.log("delayed requests pending, not closing spider") 
      raise DontCloseSpider() 

    def process_request(self, request, spider): 
     delay = request.meta.pop('delay_request', None) 
     if delay: 
      self.requests.setdefault(spider, 0) 
      self.requests[spider] += 1 
      reactor.callLater(delay, self.schedule_request, request.copy(), 
           spider) 
      raise IgnoreRequest() 

    def schedule_request(self, request, spider): 
     spider.crawler.engine.schedule(request, spider) 
     self.requests[spider] -= 1 

und kann wie in Parse verwendet werden:

yield Request(..., meta={'delay_request': 5})