2010-03-07 16 views
12

Ich muss eine benutzerdefinierbare Webspider/Crawler erstellen, und ich denke über die Verwendung von Scrapy. Aber ich kann die Domänen und die erlaubte URL regex: es nicht fest codieren - dies wird stattdessen in einer GUI konfigurierbar sein.Mit einem Scrapy Spider für mehrere Websites

Wie kann ich (so einfach wie möglich) eine Spinne oder eine Reihe von Spidern mit Scrapy erstellen, wo die Domains und die erlaubten URL-Regexs dynamisch konfigurierbar sind? Z.B. Ich schreibe die Konfiguration in eine Datei und die Spinne liest sie irgendwie.

+2

@Christian Daven: War nicht die Antworten für Ihre Frage akzeptabel? – dangra

Antwort

10

WARNUNG: Diese Antwort war für Scrapy v0.7, Spider Manager API hat sich seitdem sehr geändert.

außer Kraft setzen Standard SpiderManager Klasse, laden Sie Ihre benutzerdefinierten Regeln aus einer Datenbank oder sonstwo und instanziiert eine eigene Spinne mit Ihren eigenen Regeln/reguläre Ausdrücke und domain_name

in mybot/settings.py:

SPIDER_MANAGER_CLASS = 'mybot.spidermanager.MySpiderManager' 

in mybot/spidermanager.py:

from mybot.spider import MyParametrizedSpider 

class MySpiderManager(object): 
    loaded = True 

    def fromdomain(self, name): 
     start_urls, extra_domain_names, regexes = self._get_spider_info(name) 
     return MyParametrizedSpider(name, start_urls, extra_domain_names, regexes) 

    def close_spider(self, spider): 
     # Put here code you want to run before spiders is closed 
     pass 

    def _get_spider_info(self, name): 
     # query your backend (maybe a sqldb) using `name` as primary key, 
     # and return start_urls, extra_domains and regexes 
     ... 
     return (start_urls, extra_domains, regexes) 

und jetzt Klasse Ihrer individuellen Spinne, in mybot/spider.py:

from scrapy.spider import BaseSpider 

class MyParametrizedSpider(BaseSpider): 

    def __init__(self, name, start_urls, extra_domain_names, regexes): 
     self.domain_name = name 
     self.start_urls = start_urls 
     self.extra_domain_names = extra_domain_names 
     self.regexes = regexes 

    def parse(self, response): 
     ... 

Hinweise:

  • Sie können CrawlSpider verlängern, wenn Sie die Vorteile seiner Geschäfts System
  • nehmen wollen eine Spinne Verwendung auszuführen: ./scrapy-ctl.py crawl <name>, wo name zu SpiderManager.fromdomain geleitet wird und ist der Schlüssel, um mehr Spider-Informationen aus dem Backend-System zu retriezen
  • Als Lösung überschreibt Standard-SpiderManager, Codierung ein klassisches Spider (ein Python-Modul pro SPIDER) funktioniert nicht, aber ich denke, das ist kein Problem für Sie.Weitere Informationen über Standard-Spinnen-Manager TwistedPluginSpiderManager
+0

Der Unterschied zum Ansatz von Alex Martelli besteht darin, dass die Spider bei Bedarf instanziiert werden, anstatt sie alle vorzufüh- ren, nur um einen zu verwenden. Dieser Ansatz kann die Belastung Ihres Back-Ends und des Speicherbedarfs Ihres Scrap-Bot-Prozesses reduzieren. – dangra

+0

Und wie definiere ich Einstellungen für benutzerdefinierte Spider (ITEM_PIPELINES, USER_AGENT usw.)? Auch Sie erwähnen './scrapy-ctl.py crawl '. Was ist "scrapy-ctl.py"? – warvariuc

3

Schamlose Selbstwerbung auf domo! Sie müssen den Crawler gemäß den Beispielen für Ihr Projekt instanziieren.

Außerdem müssen Sie den Crawler zur Laufzeit konfigurierbar machen, indem Sie einfach die Konfiguration an Crawler übergeben und die Einstellungen zur Laufzeit überschreiben, wenn sich die Konfiguration ändert.

4

Was Sie brauchen, ist dynamisch Spinne Klassen zu erstellen, Ihre Lieblings-generic Spinne Klasse Subklassen wie von scrapy geliefert (CrawlSpider Subklassen mit Ihrem rules hinzugefügt oder XmlFeedSpider, oder was auch immer) und das Hinzufügen von domain_name, start_urls und möglicherweise extra_domain_names (und/oder start_requests(), usw.), wie Sie sie von Ihrer GUI (oder Konfigurationsdatei oder was auch immer) erhalten oder ableiten.

Python erleichtert die dynamische Erstellung von Klassenobjekten. ein sehr einfaches Beispiel könnte sein:

from scrapy import spider 

def makespider(domain_name, start_urls, 
       basecls=spider.BaseSpider): 
    return type(domain_name + 'Spider', 
       (basecls,), 
       {'domain_name': domain_name, 
       'start_urls': start_urls}) 

allspiders = [] 
for domain, urls in listofdomainurlpairs: 
    allspiders.append(makespider(domain, urls)) 

Dies gibt Ihnen eine Liste von sehr nackten Knochen Spinne Klassen - Sie werden wahrscheinlich wollen parse Methoden um sie hinzuzufügen, bevor Sie sie instanziiert. Nach Geschmack würzen...;-).

+0

und wo würde dieser Code leben? Ich habe versucht, Crawler-Klassen dynamisch zu meinen Spider-Modulen hinzuzufügen, aber scrapy nimmt sie nicht auf. –

0

Jetzt ist es extrem einfach scrapy für diese Zwecke zu konfigurieren:

  1. über den ersten Urls zu besuchen, können Sie es als ein Attribut auf der Spinne Anruf passieren können mit -a, und verwenden Sie die start_requests Funktion einrichten, wie die Spinne

  2. Sie beginnen nicht einrichten müssen die allowed_domains Variable für die Spinnen. Wenn Sie diese Klassenvariable nicht einschließen, kann die Spinne jede Domäne zulassen.

Es sollte so etwas wie Ende:

class MySpider(Spider): 

    name = "myspider" 

    def start_requests(self): 
     yield Request(self.start_url, callback=self.parse) 


    def parse(self, response): 
     ... 

und Sie sollten es mit nennen:

scrapy crawl myspider -a start_url="http://example.com" 
Verwandte Themen