2017-12-22 4 views
2

Ich arbeite mit Scrapy und Sqlalchemy. In meiner Spinne aus einer Tabelle Ich bin der Auswahl und Erstellung von Anfragen mit:Aktualisieren Tabelle Zeile mit Sqlalchemy in Scrapy

def start_requests(self): 

    db_path = "sqlite:///"+settings.SETTINGS_PATH+"\\data.db" 
    source_table= self.table 

    engine = create_engine(db_path) 
    Base = declarative_base() 
    # metadata = Base.metadata 
    # Look up the existing tables from database 
    Base.metadata.reflect(engine) 

    # Create class that maps via ORM to the database table 
    table = type(source_table, (Base,), {'__tablename__': source_table}) 

    Session = sessionmaker(bind=engine) 
    session = Session() 
    i = 0 

for row in session.query(table).filter(table.url.contains('http')).limit(3): 

    i += 1 
    print(row.url) 
    yield Request(url=row.url, headers= headers, callback=self.get_PDF,meta={'session': session,'row': row, 'cookiejar': i },dont_filter = True) 

Wie Sie bin ich vorbei eine sqlalchemy Zeilenobjekt mit jedem scrapy Anfrage sehen können. Jedes Zeilenobjekt enthält leere Felder, die ich von der Scrapy-Antwort aktualisiere.

Jetzt möchte ich das Zeilenobjekt aktualisieren, damit seine Änderungen in der Datenbank gespeichert werden. Wenn ich das Sitzungsobjekt übergeben würde, könnte ich session.commit() ausführen. Was ist der beste Weg, dies mit einem row_object zu tun? Muss ich das Sitzungsobjekt übergeben?

edit: Ich habe meine Spinne passieren das Sitzungsobjekt geändert:

def get_PDF(self, response): 

    row = response.meta['row'] 
    session = response.meta['session'] 

    row =process_output(o, row) 
    session.add(row) 
    session.commit() 

Antwort

3

würde ich die beste Art und Weise sagen, immer Datenbank und „externe“ Speicher behandeln würde mit einem Pipeline sein, da es sich um ein Möglichkeit, die Logik des Codes zu trennen. Die Pipeline verarbeitet nur Objekte, die von der Spinne zurückgegeben werden, sodass Sie sich keine Gedanken über Anfragen oder etwas im Spider-Code machen müssen.

Auch eine Pipeline erstellt ein Objekt, das dem Crawler zugeordnet ist, und es wird nur einmal instanziiert, was für diese Situation sehr hilfreich sein kann.

Wenn Sie Elemente anders behandeln müssen, könnten Sie immer eine eindeutige Kennung an jedes Element senden, damit die Pipeline weiß, wie mit jedem Element verfahren wird.

EDIT: für die Erstellung der Session Objekt innerhalb der Spinne, und es in der Pipeline Wiederverwendung, können Sie etwas tun:

Spider:

def start_requests(self): 
    self.session = Session() 

Pipeline

def process_item(self, item, spider): 
    ... 
    spider.session.commit() 

Das spider ist die "eindeutige" Spider-Instanz des gesamten Crawlers, also können Sie dort seine Attribute verwenden.

+0

Sie können das Session-Objekt innerhalb der Spinne erstellen (z. B. in 'start_requests') und es immer noch für die Pipeline verwenden. – eLRuLL

+0

@ user61629 Überprüfen Sie meine aktualisierte Antwort – eLRuLL

+0

siehe meine Bearbeitung oben. Das funktioniert, aber ich bin besorgt über das Erstellen mehrerer Kopien des Sitzungsobjekts, also sehe ich Ihren Punkt über die Verwendung von Pipelines. In diesem Fall habe ich einen 2-stufigen Prozess. Meine erste Spinne bekommt 90% der Informationen, die die Gegenstände mit einigen leeren Feldern füllen. Dann verwende ich eine zweite Spinne, um eine zeitintensivere Operation durchzuführen, um die letzten 2 Felder zu füllen. Ich benutze Items und Pipelines für die erste Spinne, aber es schien so, als könnte ich mit sqlalchemy direkt viel weniger Code durchkommen, anstatt Zeilen in Objekte zu verwandeln und sie dann zum zweiten Mal durch die Pipeline zu schicken. – user61629

Verwandte Themen