2013-08-21 8 views
9

Um weiter auf die Überschrift für diese Frage: Ich kratze Informationen von Film Website. Ich habe zZ eine MySQL Datenbank, die mit movie titles, , etc. gefüllt wird. Ich nehme jetzt diese urls von der Datenbank und setze sie als meine start_urls innerhalb einer neuen spider. Jede url ist ein Link zu der Webseite [destritrary movie], die viel mehr Informationen vermittelt. Die Informationen, die ich interessiert bin ist:Scrapy: Vorschlag für mehrere Rücksendungen/Artikel zur Datenbank

  • Verteiler (dh Fox.)
  • Bewertung
  • Direktor
  • Genre (dh Komödie.)
  • Schauspieler
  • (dh Pg-13.)
  • Produzent/s

Von diesen, Händler, Bewertung, Regisseur und Genre wird ein 'Ding' mit ihnen verbunden haben f von jeder Filmwebseite (eine Bewertung, ein Regisseur, usw.). Es wird mehrere, natürlich, mehrere Schauspieler und, abhängig, mehrere Produzenten geben (größere Namen Filme/die meisten Filme). Hier habe ich ein Problem. Ich möchte eine pipeline' which puts each piece of info in an appropriate Tabelle within my MySQL database. So, a table for director, a table for rating, etc. Each table will also have Filmtitel einrichten. Ich kann das Problem selbst so sagen:

Ich habe Probleme beim Ausgleichen, wie man eine geeignete pipeline mit einer entsprechenden spider erstellen. Ich bin mir nicht sicher, ob ich mehrere Dinge von einem Spider zurückgeben und sie an verschiedene pipelines (verschiedene Elemente zum Umgang mit single Attribute, und ein anderes Element, um mit 'multiple' Attribute umzugehen) senden oder ob die gleiche Pipeline verwenden und irgendwie angeben, was wo geht (nicht sicher, ob ich nach dem Kratzen nur noch eins zurückgeben kann). Ich werde meinen Code zeigen und hoffentlich wird das Problem klarer werden. * Hinweis: Es ist noch nicht Komplett- ist Ich versuche nur zu füllen die Lücken mit, wie diese

Spinne zu tun:

class ActorSpider(BaseSpider): 
    import sys; sys.path.append("/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages") 
    import MySQLdb 
    db = MySQLdb.connect(db = 'testdb', user='testuser', passwd='test') 
    dbc = db.cursor() 
    name = 'ActorSpider' 
    allowed_domains = ['movie website'] 
    #start_urls = #HAVE NOT FILLED THIS IN YET- WILL BE A SELECT STATEMENT, GATHERING ALL URLS 

    def parse(self, response): 

     hxs = HtmlXPathSelector(response) 

     #Expect only singular items (ie. one title, one rating, etc.) 

     single_info = SingleItem() 
     title = hxs.select('[title tags here]').extract() 
     distributor = hxs.select('[distributor tags here]').extract() 
     rating = hxs.select('[rating tags here]').extract() 
     director = hxs.select('[director tags here]').extract() 
     genre = hxs.select('[genre tags here]').extract() 

     single_items = [] 
     single_info['title'] = title 
     single_info['distributor'] = distributor 
     single_info['rating'] = rating 
     single_info['director'] = director 
     single_info['genre'] = genre   
     single_items.append(single_info) #Note: not sure if I want to return this or the single info 

     #return single_items 


     #Multiple items in a field 

     multi_info = MultiItem() 
     actors = hxs.select('[actor tags here]').extract() 
     producers = hxs.select('[producer tags here]').extract() 

     actor_items= [] 
     for i in range(len(actors)): 
      multi_info['title'] = title 
      multi_info['actor'] = actors[i] 
      actor_items.append(multi_info) 

    #return actor_items - can I have multiple returns in my code to specify which pipeline is used, or which table this should be inserted into 

     producer_items = [] 
     for i in range(len(producers)): 
      multi_info['title'] = title 
      multi_info['producer'] = producers[i] 
      producer_items.append(multi_info) 
     #return producer_items - same issue - are multiple returns allowed? Should I try to put both the 'single items' and 'multiple items' in on big 'items' list? Can scrapy figure that out or how would I go about specifying? 

ich in einer Reihe von Fragen kommentiert haben, die unklar sein kann, - Ich bin mir nicht sicher, wie ich alles ansteuern soll, damit es in der entsprechenden Tabelle landet. Dies kann klarer sein, wenn Sie die Pipeline lesen, das ist:

class IndMoviePipeline(object): 

    def __init__(self): 
     'initiate the database connnection' 
     self.conn = MySQLdb.connect(user='testuser', passwd='test', db='testdb', host='localhost', charset='utf8', use_unicode=True) 
     self.cursor = self.conn.cursor() 

    def process_item(self, item, spider): 

     try: 
      if 'producer' in item: 
        self.cursor.execute("""INSERT INTO Producers (title, producer) VALUES (%s, %s)""", (item['title'], item['producer'])) 
      elif 'actor' in item: 
        self.cursor.execute("""INSERT INTO Actors (title, actor) VALUES (%s, %s)""", (item['title'], item['actor'])) 
      else: 
        self.cursor.execute("""INSERT INTO Other_Info (title, distributor, rating, director, genre) VALUES (%s, %s, %s, %s, %s)""", (item['title'], item['distributor'], item['rating'], item['director'], item['genre'])) #NOTE: I will likely change 'Other_Info' table to just populating the original table from which the URLS will be pulled 
      self.conn.commit() 
     except MySQLdb.Error, e: 
      print "Error %d: %s" % (e.args[0], e.args[1]) 

     return item 

denke ich, dass die item an die entsprechenden table innerhalb der Datenbank zu lenken arbeiten. Auf dieser Grundlage, ich glaube, es wäre eine große Liste von items arbeiten zu lassen und alle an ihm anhängen, so:

items = [] 
items.append(single_info) 

for i in range(len(producers)): 
     multi_info['title'] = title 
     multi_info['producer'] = producers[i] 
     items.append(multi_info) 

for i in range(len(actors)): 
     multi_info['title'] = title 
     multi_info['actor'] = actors[i] 
     items.append(multi_info) 

Nur lassen die pipeline Art alle diese aus mit diesen if Aussagen. Ich bin mir allerdings nicht sicher, ob dies der beste Weg ist und würde mich über Vorschläge freuen.

Antwort

12

Konzeptuell, scrapy Items beziehen sich im Allgemeinen auf ein einzelnes "Ding", das geschabt wird (in Ihrem Fall ein Film) und haben Felder, die die Daten darstellen, die dieses "Ding" ausmachen.So prüfen mit:

class MovieItem(scrapy.item.Item): 
    title = Field() 
    director = Field() 
    actors = Field() 

Dann, wenn Sie die Einzelteile kratzen:

item = MovieItem() 

title = hxs.select('//some/long/xpath').extract() 
item['title'] = title 

actors = hxs.select('//some/long/xpath').extract() 
item['actors'] = actors 

return item 

Spinne Parse-Methoden sollten immer zurückkehren oder entweder ergeben scrapy.item.Item Objekte oder scrapy.http.Request Objekte.

Von dort hängt es ab, wie Sie die MovieItems verarbeiten. Sie könnten für jede Eigenschaft des MovieItem eine Pipeline haben, dies wird jedoch nicht empfohlen. Was ich stattdessen empfehlen würde, ist ein einzelnes MySQLPersistancePipeline-Objekt, das über Methoden verfügt, um jedes der Felder von MovieItem persistent zu machen. So etwas wie:

class MySQLPersistancePipeline(object): 
    ... 
    def persist_producer(self, item): 
    self.cursor.execute('insert into producers ...', item['producer']) 

    def persist_actors(self, item): 
    for actor in item['actors']: 
     self.cursor.execute('insert into actors ...', actor) 

    def process_item(self, item, spider): 
    persist_producer(item) 
    persist_actors(item) 
    return item 
+0

Vielen Dank für die Zeit zu reagieren! Ich werde es überprüfen und sehen, wie es geht - wird als gelöst gewertet, wenn es gut ist! Danke noch einmal! – DMML

+0

Greate Antwort, @audiodude! Warum werden mehrere Pipelines nicht empfohlen? –

Verwandte Themen