Ich sehe keinen guten Grund zu tun, was Sie tun :) Sie können die json_filename
Einstellung ändern, indem Sie Argumente auf Ihrem scrapyd schedule.json
Anfrage festlegen. Dann können Sie jede Spinne dazu bringen, leicht unterschiedliche Dateien zu generieren, die Sie mit der Nachbearbeitung oder zur Abfragezeit zusammenführen. Sie können JSON-Dateien auch ähnlich wie bei Ihnen schreiben, indem Sie einfach den Wert FEED_URI
(example) eingeben. Wenn Sie aus mehreren Prozessen gleichzeitig in eine einzelne Datei schreiben (insbesondere wenn Sie mit 'wb'
starten), suchen Sie nach beschädigten Daten.
Edit:
Nach ein bisschen besser zu verstehen, was Sie brauchen - in diesem Fall - es ist scrapyd starten mehrere kriecht verschiedene Spinnen laufen, wo jeder eine andere Website kriecht. Der Consumer-Prozess überwacht kontinuierlich eine einzelne Datei.
Es gibt verschiedene Lösungen, darunter:
relativ einfach für sehr kleine Gegenstände und ok zu implementieren nur (see here)
- RabbitMQ oder ein anderer Warteschlangenmechanismus
Große Lösung, aber könnte ein bisschen übertrieben sein
- Eine Datenbank z. SQLite-basierte Lösung
Schön und einfach, erfordert aber wahrscheinlich einige Codierung (individuelle Verbraucher)
- Eine schöne
inotifywait
-basierte oder andere Dateisystem-Monitoring-Lösung
Nizza und wahrscheinlich leicht
zu implementieren
Der letzte scheint die attraktivste Option für mich. Wenn scrapy crawl
beendet wird (spider_closed signal), verschieben, kopieren oder erstellen Sie einen Softlink für die Datei FEED_URL
in ein Verzeichnis, das Sie mit einem Skript wie this überwachen. mv
oder ln
ist eine atomare Unix-Operation, so sollten Sie in Ordnung sein. Hacken Sie das Skript, um die neue Datei an Ihre tmp
Datei anzuhängen, die Sie einmal an Ihr Verbraucherprogramm senden.
Mit dieser Methode verwenden Sie die Standard-Feed-Exporteure, um Ihre Dateien zu schreiben. Die Endlösung ist so einfach, dass Sie keine Pipeline benötigen. Eine einfache Erweiterung sollte die Rechnung erfüllen.
Auf einem extensions.py
im selben Verzeichnis wie settings.py
:
from scrapy import signals
from scrapy.exceptions import NotConfigured
class MoveFileOnCloseExtension(object):
def __init__(self, feed_uri):
self.feed_uri = feed_uri
@classmethod
def from_crawler(cls, crawler):
# instantiate the extension object
feed_uri = crawler.settings.get('FEED_URI')
ext = cls(feed_uri)
crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
# return the extension object
return ext
def spider_closed(self, spider):
# Move the file to the proper location
# os.rename(self.feed_uri, ... destination path...)
Auf Ihrem settings.py
:
EXTENSIONS = {
'myproject.extensions.MoveFileOnCloseExtension': 500,
}
Vielen Dank für Ihre Antwort. Ich denke, ich verstehe nicht gut, wie Pipelines in scrapy arbeiten. Nach meinem Verständnis generiert der Spider Items, die Items aller Spider werden an die Pipeline weitergeleitet, die für alle global ist, und sie verarbeiten. Aus Ihrer Antwort gehe ich davon aus, dass jede Spinne eine eigene Pipeline hat und mehrere Pipelines mit derselben Datei arbeiten, was zu Problemen führt. Habe ich recht? . Ich mache es auf diese Weise, weil es einen anderen Prozess gibt, der etwas mit dem Inhalt macht und nur eine Datei akzeptiert. – silvestrelosada
Die Phrasierung ist nicht 100% genau, aber was Sie sagen, ist richtig. Genauer gesagt führt Scrapyd mehrere Scrapy-Prozesse parallel durch. Jeder Scrapy-Prozess führt eine Spinne und deine Pipeline aus. Dies bedeutet, dass Sie während dieses Crawls dieselbe Datei öffnen, um von vielen Prozessen zu schreiben, was zu Korruption führt. "... akzeptiert nur eine Datei". Ich bin mir sicher, dass es einen besseren Weg gibt, dies zu tun. Kannst du Scrapyd laufen lassen? 100 Dateien daraus, [concat sie zu einem] (http://stackoverflow.com/questions/4969641/append-one-file-to-another-in-linux) und dann das zu Ihrem Prozess füttern? Dies ist viel häufiger. – neverlastn
Kennen Sie eine Option, um das Ergebnis (Elemente) aller Spider auf dieselbe Datei mit nur scrappy zu setzen? Dank – silvestrelosada