2015-01-06 4 views

Antwort

8

Scrapy bietet nichts dergleichen. Sie können set the DEPTH_LIMIT per-spider, aber nicht per-Domäne.

Was können wir tun? Read the code, Kaffee trinken und lösen (Bestellung ist wichtig).

Die Idee ist, Scrapy eingebaute DepthMiddleware und provide our custom one stattdessen zu deaktivieren.

Lassen Sie uns zunächst Einstellungen definieren:

  • DOMAIN_DEPTHS ein Wörterbuch mit Tiefengrenzen pro Domain
  • DEPTH_LIMIT Einstellung sein würden wir als Standard ein, falls verlassen werde eine Domäne nicht konfiguriert ist

Beispiel Einstellungen:

DOMAIN_DEPTHS = {'amazon.com': 1, 'homedepot.com': 4} 
DEPTH_LIMIT = 3 

Okay, jetzt die benutzerdefinierte Middleware (basierend auf DepthMiddleware):

from scrapy import log 
from scrapy.http import Request 
import tldextract 


class DomainDepthMiddleware(object): 
    def __init__(self, domain_depths, default_depth): 
     self.domain_depths = domain_depths 
     self.default_depth = default_depth 

    @classmethod 
    def from_crawler(cls, crawler): 
     settings = crawler.settings 
     domain_depths = settings.getdict('DOMAIN_DEPTHS', default={}) 
     default_depth = settings.getint('DEPTH_LIMIT', 1) 

     return cls(domain_depths, default_depth) 

    def process_spider_output(self, response, result, spider): 
     def _filter(request): 
      if isinstance(request, Request): 
       # get max depth per domain 
       domain = tldextract.extract(request.url).registered_domain 
       maxdepth = self.domain_depths.get(domain, self.default_depth) 

       depth = response.meta.get('depth', 0) + 1 
       request.meta['depth'] = depth 

       if maxdepth and depth > maxdepth: 
        log.msg(format="Ignoring link (depth > %(maxdepth)d): %(requrl)s ", 
          level=log.DEBUG, spider=spider, 
          maxdepth=maxdepth, requrl=request.url) 
        return False 
      return True 

     return (r for r in result or() if _filter(r)) 

Beachten Sie, dass es tldextract Modul (verwendet, um einen Domain-Namen von URL zum Extrahieren) installiert werden benötigt:

>>> import tldextract 
>>> url = 'http://stackoverflow.com/questions/27805952/scrapy-set-depth-limit-per-allowed-domains' 
>>> tldextract.extract(url).registered_domain 
'stackoverflow.com' 

Jetzt brauchen wir um die Standard-Middleware auszuschalten und die von uns implementierte zu verwenden:

SPIDER_MIDDLEWARES = { 
    'myproject.middlewares.DomainDepthMiddleware': 900, 
    'scrapy.contrib.spidermiddleware.depth.DepthMiddleware': None 
} 
+0

Wie unterscheidet sich tldextract von dem bekannteren Python-Paket 'tld'? –

+2

@FredericBazin Ich bin mir nicht wirklich sicher, habe sie nicht verglichen. Ich denke hier ist es nicht sehr wichtig. Sie können jedes von ihnen verwenden oder es sogar mit 'urlparse()' lösen, das eine Gewohnheit 'extract_domain()' Funktion hat. Vielen Dank. – alecxe

+0

Vielen Dank für eine großartige Erklärung! Sollte 'response.meta ['depth'] = 0 'über' depth = response.meta [' depth '] + 1' Else, ist' response.meta ['depth'] 'leer und würde einen Keyerror geben –