1

複数のスパイダーを同時に実行している Scrapyd サーバーがあり、schedule.json エンドポイントを使用してスパイダーを 1 つずつ起動します。すべてのスパイダーは、パイプラインを使用して共通ファイルにコンテンツを書き込んでいます

class JsonWriterPipeline(object):

def __init__(self, json_filename):
    # self.json_filepath = json_filepath
    self.json_filename = json_filename
    self.file = open(self.json_filename, 'wb')

@classmethod
def from_crawler(cls, crawler):
    save_path='/tmp/'
    json_filename=crawler.settings.get('json_filename', 'FM_raw_export.json')
    completeName = os.path.join(save_path, json_filename) 
    return cls(
        completeName
    )

def process_item(self, item, spider):
    line = json.dumps(dict(item)) + "\n"
    self.file.write(line)
    return item

スパイダーが実行されると、データが正しく収集され、アイテムがファイル XXXX.jl に保存され、スパイダーが正しく動作することがわかりますが、クロールされたコンテンツは共通ファイルに反映されません。スパイダーはうまく機能しているように見えますが、パイプラインはうまく機能しておらず、共通ファイルにデータを収集していません。

また、同時にファイルに書き込みを行っているのは 1 つのスパイダーだけであることに気付きました。

4

1 に答える 1

1

あなたがしていることをする正当な理由はわかりません:)設定は、scrapydリクエストjson_filenameに引数を設定することで変更できます。schedule.json次に、後処理またはクエリ時にマージするわずかに異なるファイルを各スパイダーに生成させることができます。値を設定するだけで、持っているものと同様の JSON ファイルを作成することもできますFEED_URI( example )。複数のプロセスから同時に単一のファイルに書き込む場合 (特に'wb'モードで開く場合)、破損したデータを探しています。

編集:

必要なものを少しよく理解した後 (この場合)、それぞれが異なる Web サイトをクロールする異なるスパイダーを実行する複数のクロールを開始するのは、scrapyd です。コンシューマー プロセスは、1 つのファイルを継続的に監視しています。

次のようないくつかのソリューションがあります。

  • 名前付きパイプ

実装が比較的簡単で、非常に小さなアイテムのみに使用できます (こちらを参照)

  • RabbitMQ またはその他のキューイング メカニズム

優れたソリューションですが、少しやり過ぎかもしれません

  • SQLite ベースのソリューションなどのデータベース

素晴らしくシンプルですが、コーディングが必要になる可能性があります (カスタム コンシューマー)

  • niceinotifywaitベースまたはその他のファイルシステム監視ソリューション

素晴らしく、おそらく簡単に実装できます

最後のオプションは、私にとって最も魅力的なオプションのようです。終了したらscrapy crawl( Spider_closed シグナル)、このFEED_URLようなスクリプトで監視するディレクトリにファイルのソフト リンクを移動、コピー、または作成します。またはアトミックUNIX操作なので、問題ないはずです。スクリプトをハックして、コンシューマー プログラムに一度フィードするファイルに新しいファイルを追加します。mvlntmp

この方法を使用すると、デフォルトのフィード エクスポーターを使用してファイルを書き込むことができます。最終的なソリューションは非常に単純なので、パイプラインは必要ありません。シンプルな拡張機能で十分です。

extensions.pyと同じディレクトリにある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...)

あなたのsettings.py

EXTENSIONS = {
    'myproject.extensions.MoveFileOnCloseExtension': 500,
}
于 2016-03-24T16:32:02.370 に答える