2015-09-23 9 views
10

Ich habe einen Spider, der Daten abschabt, die nicht in einer Elementklasse gespeichert werden können.Scrapy, Python: Mehrere Item-Klassen in einer Pipeline?

Zur Veranschaulichung habe ich ein Profilelement, und jedes Profilelement kann eine unbekannte Anzahl von Kommentaren haben. Deshalb möchte ich Profil Item und Comment Item implementieren. Ich weiß, dass ich sie einfach mithilfe von Yield an meine Pipeline weitergeben kann.

  1. Allerdings weiß ich nicht, wie eine Pipeline mit einer parse_item-Funktion zwei verschiedene Elementklassen behandeln kann?

  2. Oder ist es möglich, verschiedene parse_item-Funktionen zu verwenden?

  3. Oder muss ich mehrere Pipelines verwenden?

  4. Oder ist es möglich, einen Iterator in ein Scrapy Item Field zu schreiben?


comments_list=[] 
comments=response.xpath(somexpath) 
for x in comments.extract(): 
     comments_list.append(x) 
    ScrapyItem['comments'] =comments_list 

Antwort

1

Der einfachste Weg ist der Parser umfasst zwei Unter Parser zu haben, eine für jeden Datentyp. Der Hauptparser bestimmt den Typ aus der Eingabe und übergibt die Zeichenfolge an die entsprechende Subroutine.

Ein zweiter Ansatz besteht darin, die Parser in Reihenfolge zu integrieren: man analysiert Profile und ignoriert alles andere; der zweite analysiert Kommentare und ignoriert alles andere (das gleiche Prinzip wie oben).

Bewegt Sie das vorwärts?

9

Standardmäßig geht jedes Element durch jede Pipeline.

Zum Beispiel, wenn Sie eine ProfileItem und eine CommentItem ergeben, werden sie beide durch alle Pipelines gehen. Wenn Sie eine Pipeline Setup Spuren Elementtypen haben, dann process_item Methode könnte wie folgt aussehen:

def process_item(self, item, spider): 
    self.stats.inc_value('typecount/%s' % type(item).__name__) 
    return item 

Wenn ein ProfileItem durchkommt, 'typecount/ProfileItem' erhöht wird. Wenn ein CommentItem durchkommt, wird 'typecount/CommentItem' inkrementiert.

Sie können eine Pipeline Griff nur eine Art von Elementanforderung haben, obwohl, wenn der Typ dieses Element Handhabung einzigartig ist, durch den Elementtyp, bevor Sie fortfahren Überprüfung:

def process_item(self, item, spider): 
    if not isinstance(item, ProfileItem): 
     return item 
    # Handle your Profile Item here. 

Wenn Sie hatte die beiden process_item Methoden oben Setup in verschiedenen Pipelines, wird das Element durch beide gehen, verfolgt und verarbeitet werden (oder auf der zweiten ignoriert).

Zusätzlich können Sie eine Pipeline-Setup haben alle ‚verbunden sind‘ Artikel zu handhaben:

def process_item(self, item, spider): 
    if isinstance(item, ProfileItem): 
     return self.handleProfile(item, spider) 
    if isinstance(item, CommentItem): 
     return self.handleComment(item, spider) 

def handleComment(item, spider): 
    # Handle Comment here, return item 

def handleProfile(item, spider): 
    # Handle profile here, return item 

Oder Sie es noch komplexer machen könnte und eine Art Delegation System zu entwickeln, die Klassen und ruft Standard-Handler Methoden lädt, ähnlich wie Scrapy Middleware/Pipelines behandelt. Es liegt wirklich an Ihnen, wie komplex Sie es brauchen und was Sie tun möchten.

5

Definieren mehrerer Elemente Es ist eine knifflige Sache, wenn Sie Ihre Daten exportieren, wenn sie eine Beziehung haben (Profil 1 - N Kommentare zum Beispiel) und Sie müssen sie zusammen exportieren, da jedes Element zu verschiedenen Zeiten von den Pipelines verarbeitet wird . Ein alternativer Ansatz für dieses Szenario ist ein benutzerdefinierter Scrapy Feld zum Beispiel zu definieren:

class CommentItem(scrapy.Item): 
    profile = ProfileField() 

class ProfileField(scrapy.item.Field): 
    # your business here 

Aber das Szenario gegeben, in dem Sie 2 Einzelteile haben müssen, ist es dringend empfohlen, eine andere Pipeline für jeden dieser Typen zu verwenden, Artikel und andere Exporteur Fällen auch so, dass Sie diese Informationen in verschiedenen Dateien (wenn Sie Dateien verwenden):

settings.py

ITEM_PIPELINES = { 
    'pipelines.CommentsPipeline': 1, 
    'pipelines.ProfilePipeline': 1, 
} 

pipeline.py

class CommentsPipeline(object): 
    def process_item(self, item, spider): 
     if isinstance(item, CommentItem): 
      # Your business here 

class ProfilePipeline(object): 
    def process_item(self, item, spider): 
     if isinstance(item, ProfileItem): 
      # Your business here