2012-05-15 12 views
6

Ich verwende Scrapy, insbesondere CrawlSpider Klasse Scrapy Web-Links zu kratzen, die bestimmte Schlüsselwörter enthalten. Ich habe eine ziemlich lange start_urls Liste, die ihre Einträge von einer SQLite-Datenbank erhält, die mit einem Django-Projekt verbunden ist. Ich möchte die abgeschabten Weblinks in dieser Datenbank speichern.Zugriff auf eine bestimmte start_url in einem Scrapy CrawlSpider?

Ich habe zwei Modelle Django, ein für den Start Urls wie http://example.com und eine für die geschabt Web-Links wie http://example.com/website1, http://example.com/website2 usw. Alle geschabt Web-Links sind subsites einer des Start-URLs in der Liste start_urls.

Das Web-Links-Modell hat eine Viele-zu-Eins-Beziehung zum Start-URL-Modell, d. H. Das Web-Links-Modell hat einen Fremdschlüssel zum Start-URL-Modell. Um meine geschabten Weblinks korrekt in der Datenbank zu speichern, muss ich die Methode parse_item() mitteilen, welche Startadresse die gesperrte Webverbindung enthält. Wie kann ich das machen? Scrapys DjangoItem Klasse hilft in dieser Hinsicht nicht, da ich die verwendete Start-URL immer noch explizit definieren muss.

Mit anderen Worten, wie kann ich die aktuell verwendete Start-URL an die parse_item()-Methode übergeben, so dass ich es zusammen mit den entsprechenden ausgekratzten Web-Links in die Datenbank speichern kann? Irgendwelche Ideen? Danke im Voraus!

+0

Können Sie haben das START_URL Feld in derselben Tabelle wie die Web-Links-Tabelle (wie in der DjangoItem Sie verwenden)?Sicher, es wird redundante Denormalisierung schaffen, aber wenn Sie vermeiden möchten, explizit aufzurufen, könnte dies helfen. – zubinmehta

Antwort

8

Standardmäßig können Sie nicht die ursprüngliche Start-URL zugreifen.

Aber Sie können make_requests_from_url Methode überschreiben und die Start-URL in eine meta setzen. Dann in einer Analyse können Sie es von dort extrahieren (wenn Sie in dieser Parse-Methode nachfolgende Anfragen liefern, vergessen Sie nicht, diese Start-URL in ihnen weiterzuleiten).


Ich habe nicht mit CrawlSpider gearbeitet und vielleicht was Maxim für Sie arbeiten schon sagt, aber denken Sie daran, dass response.url die URL nach einer möglichen Umleitungen hat. Hier

ist ein Beispiel dafür, wie ich es tun würde, aber es ist nur ein Beispiel (aus dem scrapy Tutorial genommen) und wurde nicht getestet:

class MySpider(CrawlSpider): 
    name = 'example.com' 
    allowed_domains = ['example.com'] 
    start_urls = ['http://www.example.com'] 

    rules = (
     # Extract links matching 'category.php' (but not matching 'subsection.php') 
     # and follow links from them (since no callback means follow=True by default). 
     Rule(SgmlLinkExtractor(allow=('category\.php',), deny=('subsection\.php',))), 

     # Extract links matching 'item.php' and parse them with the spider's method parse_item 
     Rule(SgmlLinkExtractor(allow=('item\.php',)), callback='parse_item'), 
    ) 

    def parse(self, response): # When writing crawl spider rules, avoid using parse as callback, since the CrawlSpider uses the parse method itself to implement its logic. So if you override the parse method, the crawl spider will no longer work. 
     for request_or_item in CrawlSpider.parse(self, response): 
      if isinstance(request_or_item, Request): 
       request_or_item = request_or_item.replace(meta = {'start_url': response.meta['start_url']}) 
      yield request_or_item 

    def make_requests_from_url(self, url): 
     """A method that receives a URL and returns a Request object (or a list of Request objects) to scrape. 
     This method is used to construct the initial requests in the start_requests() method, 
     and is typically used to convert urls to requests. 
     """ 
     return Request(url, dont_filter=True, meta = {'start_url': url}) 

    def parse_item(self, response): 
     self.log('Hi, this is an item page! %s' % response.url) 

     hxs = HtmlXPathSelector(response) 
     item = Item() 
     item['id'] = hxs.select('//td[@id="item_id"]/text()').re(r'ID: (\d+)') 
     item['name'] = hxs.select('//td[@id="item_name"]/text()').extract() 
     item['description'] = hxs.select('//td[@id="item_description"]/text()').extract() 
     item['start_url'] = response.meta['start_url'] 
     return item 

Stellen Sie, wenn Sie Fragen haben. Übrigens, mit PyDevs "Gehe zur Definition" -Funktion können Sie scrapy Quellen sehen und verstehen, welche Parameter Request, make_requests_from_url und andere Klassen und Methoden erwarten. Das Einarbeiten in den Code hilft und spart Zeit, obwohl es am Anfang vielleicht schwierig erscheint.

+0

Ich denke, ich verstehe grob, was du meinst, aber ich weiß nicht wirklich, wie ich es umsetzen soll. Können Sie vielleicht ein kurzes Beispiel geben, das zeigt, wie die 'make_requests_from_url'-Methode normalerweise verwendet wird und wie sie mit der 'Parse'-Methode in Beziehung steht? Ich bin immer noch ein Anfänger. Vielen Dank! – pemistahl

+1

Dank Warwaruk, das funktioniert gut. Ich habe jedoch herausgefunden, dass nur die Methode 'make_requests_from_url' und die Konfiguration des Meta-Tags der Anfrage notwendig ist, um das zu erreichen. Ich möchte die Start-URL am Ende nicht speichern, daher macht es keinen Sinn, sie in einen Artikel zu schreiben. Wie auch immer, vielen Dank nochmal! :) – pemistahl

1

Wenn ich das Problem richtig verstehe, können Sie URL von response.url erhalten und dann schreiben Sie an item['url'].

In Spider: item['url'] = response.url

Und in der Pipeline: url = item['url'].

Oder setzen Sie response.url in meta als Warvariuc schrieb.

1

Sieht aus wie Warvariucs Antwort erfordert eine leichte Änderung ab Scrapy 1.3.3: Sie müssen _parse_response anstelle von parse überschreiben. Das Überschreiben make_requests_from_url ist nicht mehr erforderlich.

Verwandte Themen