2017-10-11 10 views
2

Je voudrais répéter à plusieurs reprises les mêmes URL avec différents délais. Après avoir étudié le problème, il est apparu que la solution appropriée était d'utiliser quelque chose commeDemandes différées dans scrapy

nextreq = scrapy.Request(url, dont_filter=True) 
d = defer.Deferred() 
delay = 1 
reactor.callLater(delay, d.callback, nextreq) 
yield d 

dans l'analyse.

Cependant, j'ai été incapable de faire ce travail. Je reçois le message d'erreur ERROR: Spider must return Request, BaseItem, dict or None, got 'Deferred'

Je ne suis pas au courant tordu donc j'espère que je manque juste quelque chose d'évident

Y at-il une meilleure façon d'atteindre mon objectif qui ne combat pas le cadre tant?

Répondre

1

J'ai finalement trouvé une réponse dans an old PR

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

Cependant, l'araignée peut sortir en raison d'être ralenti trop tôt. Basé sur le middleware obsolète https://github.com/ArturGaspar/scrapy-delayed-requests, on peut y remédier avec

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

La dernière option, mise à jour du middleware par ArturGaspar, conduit à:

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 

et peut être utilisé dans Parse comme:

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