web-dev-qa-db-ja.com

Scrapy、Python:1つのパイプラインに複数のアイテムクラスがありますか?

1つのアイテムクラスに保存できないデータをスクレイプするスパイダーがあります。

説明のために、プロファイルアイテムが1つあり、各プロファイルアイテムのコメント数が不明な場合があります。そのため、プロファイルアイテムとコメントアイテムを実装したいと思います。イールドを使用するだけでパイプラインに渡すことができることを私は知っています。

  1. しかし、1つのparse_item関数を持つパイプラインが2つの異なるアイテムクラスをどのように処理できるかわかりませんか?

  2. または、異なるparse_item関数を使用することは可能ですか?

  3. または、複数のパイプラインを使用する必要がありますか?

  4. または、Scrapyアイテムフィールドにイテレータを書き込むことは可能ですか?


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

デフォルトでは、すべてのアイテムがすべてのパイプラインを通過します。

たとえば、ProfileItemCommentItemを生成すると、両方ともすべてのパイプラインを通過します。アイテムタイプを追跡するパイプライン設定がある場合は、process_itemメソッドは次のようになります:

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

ProfileItemが通過すると、'typecount/ProfileItem'がインクリメントされます。 CommentItemが通過すると、'typecount/CommentItem'がインクリメントされます。

1つのパイプラインで1つのタイプのアイテムリクエストのみを処理できますが、そのアイテムタイプを処理するのが一意である場合は、先に進む前にアイテムタイプを確認してください。

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

あなたが2つ持っていた場合process_item異なるパイプラインでセットアップされた上記のメソッドでは、アイテムは両方を通過し、追跡されて処理されます(または2番目のパイプラインでは無視されます)。

さらに、すべての「関連する」アイテムを処理するために1つのパイプライン設定を行うことができます。

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

または、Scrapyがミドルウェア/パイプラインを処理する方法と同様に、さらに複雑にして、クラスをロードし、デフォルトのハンドラーメソッドを呼び出す型委任システムを開発することもできます。それがどれほど複雑で、何をしたいかはあなた次第です。

12
Rejected

複数のアイテムを定義することは、データに関係がある場合(たとえば、プロファイル1--Nコメント)、データをエクスポートするときに注意が必要です。各アイテムはパイプラインによって異なる時間に処理されるため、一緒にエクスポートする必要があります。このシナリオの代替アプローチは、たとえば次のようなカスタムScrapyフィールドを定義することです。

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

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

ただし、2つのアイテムが必要なシナリオでは、このタイプのアイテムごとに異なるパイプラインを使用し、異なるエクスポーターインスタンスを使用して、この情報を異なるファイルで取得することを強くお勧めします(ファイルを使用している場合)。

settings.py

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

pipelines.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
8
gerosalesc

簡単な方法は、パーサーに2つのサブパーサーを含めることです(データ型ごとに1つ)。メインパーサーは入力からタイプを判別し、文字列を適切なサブルーチンに渡します。

2番目のアプローチは、パーサーを順番に含めることです。1つはプロファイルを解析し、他のすべてを無視します。 2番目はコメントを解析し、他のすべてを無視します(上記と同じ原則)。

これはあなたを前進させますか?

1
Prune