2013-05-21 4 views
5

Ich versuche, eine Spinne zu bauen, die effizient Textinformationen von vielen Websites kratzen konnten. Da ich ein Python-Benutzer bin, wurde ich an Scrapy verwiesen. Um jedoch große Websites zu vermeiden, Kratzen, möchte ich die Spinne begrenzen, nicht mehr als 20 Seiten eines bestimmten „Tiefe“ zu kratzen pro Website. Hier ist meine Spinne:Wie Anzahl gefolgt Seiten pro Website in Python Scrapy zu begrenzen

urls_file ist ein Pfad zu einer Textdatei mit URLs. Ich habe auch die maximale Tiefe in der Einstellungsdatei festgelegt. Hier ist mein Problem: wenn ich die CLOSESPIDER_PAGECOUNT Ausnahme schließt die Spinne, wenn die Gesamt Anzahl von geschabt Seiten (egal für welche Seite) den Ausnahmewert. Ich brauche aber Schaben zu stoppen, wenn ich gekratzt habe, sagen, 20 Seiten von jeder URL. Ich habe auch versucht, mit einer Variablen wie self.parsed_number + = 1 zu zählen, aber das hat auch nicht funktioniert - es scheint, dass scrapy nicht per URL url, sondern vermischt sie. Jede Beratung ist sehr willkommen!

Antwort

2

Ich würde pro-Klasse variabel machen, initialisieren es mit stats = defaultdict(int) und erhöhe self.stats[response.url] (oder kann der Schlüssel sein, ein Tupel wie (website, depth) in Ihrem Fall sein könnte) in parse_item.

Dies ist, wie ich das vorstellen - sollte in der Theorie funktionieren. Lass es mich wissen, wenn du ein Beispiel brauchst.

FYI, Sie können Basis-URL extrahieren und Tiefe mit Hilfe von urlparse.urlparse berechnen (siehe docs).

+1

Neuere Antwort auf eine andere Frage zeigt auf DEPTH_LIMIT Einstellung - http://Stackoverflow.com/a/18901802/263421 –

+0

@dwightgunning yup, danke für die Notiz. – alecxe

+0

was ist dann zu tun, nachdem 'self.stats [response.url]' größer als 20 ist? der Crawler wird aufhören, diese Site zu crawlen? – ningyuwhut

2

Um dies zu tun, können Sie Ihre eigene Link-Extractor-Klasse basierend auf SgmlLinkExtractor erstellen. Es sollte wie folgt aussehen:

from scrapy.selector import Selector 
from scrapy.utils.response import get_base_url 

from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor 

class LimitedLinkExtractor(SgmlLinkExtractor): 
    def __init__(self, allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(), 
       tags=('a', 'area'), attrs=('href'), canonicalize=True, unique=True, process_value=None, 
       deny_extensions=None, max_pages=20): 
     self.max_pages=max_pages 

     SgmlLinkExtractor.__init__(self, allow=allow, deny=deny, allow_domains=allow_domains, deny_domains=deny_domains, restrict_xpaths=restrict_xpaths, 
       tags=tags, attrs=attrs, canonicalize=canonicalize, unique=unique, process_value=process_value, 
       deny_extensions=deny_extensions) 

    def extract_links(self, response): 
     base_url = None 
     if self.restrict_xpaths: 
      sel = Selector(response) 
      base_url = get_base_url(response) 
      body = u''.join(f 
          for x in self.restrict_xpaths 
          for f in sel.xpath(x).extract() 
          ).encode(response.encoding, errors='xmlcharrefreplace') 
     else: 
      body = response.body 

     links = self._extract_links(body, response.url, response.encoding, base_url) 
     links = self._process_links(links) 
     links = links[0:self.max_pages] 
     return links 

Der Code dieser Unterklasse auf dem Code der Klasse SgmlLinkExtractor vollständig basiert. Ich habe soeben die Variable self.max_pages zum Klassenkonstruktor und zur Zeile hinzugefügt, die die Liste der Links am Ende der extract_links Methode abgeschnitten hat. Aber Sie können diese Liste intelligenter abschneiden.

Verwandte Themen