アイテム・ローダー

アイテムローダーは、スクレイピングされた アイテム を生成するための便利なメカニズムを提供します。 アイテムは独自の辞書のようなAPIを使用して入力できますが、アイテムローダーは、生の抽出データを割り当てる前に解析するなどの一般的なタスクを自動化することにより、スクレイピングプロセスからアイテムを入力するための、はるかに便利なAPIを提供します。

言い換えると、 アイテム はスクレイピングされたデータの コンテナ を提供し、アイテム・ローダーはそのコンテナに 格納 するメカニズムを提供します。

アイテム・ローダーは、スパイダーまたはソース形式(HTML、XMLなど))によってさまざまなフィールド・パース・ルールを拡張およびオーバーライドするための柔軟で効率的かつ簡単なメカニズムを提供するように設計されています。

アイテムを格納するためにアイテム・ローダーを使う

アイテムローダーを使用するには、最初にインスタンス化する必要があります。 dictのようなオブジェクト(Itemまたはdictなど)でインスタンス化するか、オブジェクトなしでインスタンス化できます。この場合、Itemは、 ItemLoader.default_item_class 属性で指定されたItemクラスを使用してアイテム・ローダー・コンストラクターで自動的にインスタンス化されます。

それから、通常は セレクター を使用して、あなたはアイテム・ローダーへの値の収集を開始します。 同じアイテム・フィールドに複数の値を追加できます。アイテム・ローダーは、適切な処理機能を使用して、それらの値を後で「結合」(join)する方法を知っています。

以下は、 アイテムの章 で宣言された Product item を使用した、スパイダー 内での典型的なアイテム・ローダーの使用法です:

from scrapy.loader import ItemLoader
from myproject.items import Product

def parse(self, response):
    l = ItemLoader(item=Product(), response=response)
    l.add_xpath('name', '//div[@class="product_name"]')
    l.add_xpath('name', '//div[@class="product_title"]')
    l.add_xpath('price', '//p[@id="price"]')
    l.add_css('stock', 'p#stock]')
    l.add_value('last_updated', 'today') # you can also use literal values
    return l.load_item()

そのコードをざっと見ると、ページ内の2つの異なるXPathロケーションから name フィールドが抽出されていることがわかります:

  1. //div[@class="product_name"]

  2. //div[@class="product_title"]

いいかえると、データは、 add_xpath() メソッドを使用して、2つのXPathロケーションから抽出することで収集されます。 これは後で name フィールドに割り当てられるデータです。

その後、同様の呼び出しが price および stock フィールド(後者は add_css() メソッドでCSSセレクターを使用)に対して行われ、おわりに last_update フィールドは add_value() という別のメソッドを使用して、リテラル値( today )を直接入力します:

すべてのデータが収集されると、最後に、 ItemLoader.load_item() メソッドが呼び出され、実際に返されるのは、以前に add_xpath()add_css()add_value() の呼び出しで収集したデータを格納したアイテムです。

入力プロセッサと出力プロセッサ

アイテムローダーには、各(アイテム)フィールドごとに1つの入力プロセッサと1つの出力プロセッサが含まれます。入力プロセッサは、( add_xpath() または add_css() または add_value() メソッドを介して)受信したデータをすぐに処理し、入力プロセッサの結果が収集されてアイテム・ローダー内に保持されます。すべてのデータを収集した後、 ItemLoader.load_item() メソッドが呼び出されてデータを格納し、データが格納された Item オブジェクトを取得します。その時点で、以前に収集された(および入力プロセッサを使用して処理された)データを使用して、出力プロセッサが呼び出されます。出力プロセッサの結果は、アイテムに割り当てられる最終値です。

(他の任意のフィールドにも同じことが当てはまりますが)とあるフィールドに対して入力プロセッサおよび出力プロセッサがどのように呼び出されるかを例で見てみましょう:

l = ItemLoader(Product(), some_selector)
l.add_xpath('name', xpath1) # (1)
l.add_xpath('name', xpath2) # (2)
l.add_css('name', css) # (3)
l.add_value('name', 'test') # (4)
return l.load_item() # (5)

以下のステップがあります:

  1. xpath1 からのデータが抽出され、 name フィールドの 入力プロセッサ を通過します。 入力プロセッサの結果が収集され、アイテムローダーに保持されます(ただし、アイテムにはまだ割り当てられていません)。

  2. xpath2 からのデータが抽出され、ステップ(1)で使用されたのと同じ 入力プロセッサ を通過します。 入力プロセッサの結果は、(存在する場合、)ステップ(1)で収集されたデータに追加されます。

  3. この場合は、データが css CSSセレクターから抽出され、ステップ(1)とステップ(2)で使用された同じ 入力プロセッサ を通過することを除いて、以前の場合と似ています。 入力プロセッサの結果は、(存在する場合、)ステップ(1)およびステップ(2)で収集されたデータに追加されます。

  4. この場合も以前の場合と似ていますが、XPath式またはCSSセレクターから抽出されるのではなく、収集される値が直接割り当てられる点が異なります。 ただし、値は引き続き入力プロセッサを介して渡されます。 この場合、値は反復可能ではなく(not iterable)、そして、入力プロセッサに常に反復可能要素を受け取るため(always receive iterables)、入力プロセッサに渡す前に単一の要素の反復可能要素に変換されます。

  5. ステップ(1)〜(4)で収集されたデータは、 name フィールドの 出力プロセッサ を介して渡されます。 出力プロセッサの結果は、アイテムの name フィールドに割り当てられた値です。

プロセッサは、呼び出し可能なオブジェクトであり、パースされるデータとともに呼び出され、パースされた値を返すことに注意してください。 したがって、任意の関数を入力プロセッサまたは出力プロセッサとして使用できます。 唯一の要件は、イテレータになる位置引数を1つ(そして1つだけ)受け入れる必要があることです。

注釈

入力プロセッサと出力プロセッサは両方とも、イテレータを最初の引数として受け取る必要があります。 これらの関数の出力は何でもかまいません。 入力プロセッサの結果は、(そのフィールドのために)収集された値を含む(ローダー内の)内部リストに追加されます。出力プロセッサの結果は、最終的にアイテムに割り当てられる値です。

あなたが単純な関数をプロセッサとして使用する場合は、最初の引数として self を受け取ることを確認してください:

def lowercase_processor(self, values):
    for v in values:
        yield v.lower()

class MyItemLoader(ItemLoader):
    name_in = lowercase_processor

なぜなら、これは、関数がクラス変数として割り当てられると常にメソッドになり、呼び出されたときに最初の引数としてインスタンスが渡されるためです。 詳細については、this answer on stackoverflow (https://stackoverflow.com/a/35322635)を参照してください。

もう1つ注意する必要があるのは、入力プロセッサから返される値が内部(リスト)で収集され、出力プロセッサに渡されてフィールドに入力されることです。

最後になりましたが、Scrapyには、便宜上、最小限の 一般的に使われるプロセッサ が組み込まれています。

アイテム・ローダーの宣言

アイテム・ローダーは、クラス定義構文を使用して、アイテムのように宣言されます。以下に例があります:

from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, MapCompose, Join

class ProductLoader(ItemLoader):

    default_output_processor = TakeFirst()

    name_in = MapCompose(unicode.title)
    name_out = Join()

    price_in = MapCompose(unicode.strip)

    # ...

ご覧のように、入力プロセッサは _in 接尾辞を使用して宣言され、出力プロセッサは _out 接尾辞を使用して宣言されています。 また、 ItemLoader.default_input_processorItemLoader.default_output_processor 属性を使用して、デフォルトの入出力プロセッサを宣言することもできます。

入力プロセッサと出力プロセッサの宣言

前述のとおり、入力プロセッサと出力プロセッサはアイテム・ローダー定義で宣言できます。この方法で入力プロセッサを宣言することは非常に一般的です。 ただし、使用する入力プロセッサと出力プロセッサを指定できる場所がもう1つあります。 アイテム・フィールド メタデータです。以下に例を示します:

import scrapy
from scrapy.loader.processors import Join, MapCompose, TakeFirst
from w3lib.html import remove_tags

def filter_price(value):
    if value.isdigit():
        return value

class Product(scrapy.Item):
    name = scrapy.Field(
        input_processor=MapCompose(remove_tags),
        output_processor=Join(),
    )
    price = scrapy.Field(
        input_processor=MapCompose(remove_tags, filter_price),
        output_processor=TakeFirst(),
    )
>>> from scrapy.loader import ItemLoader
>>> il = ItemLoader(item=Product())
>>> il.add_value('name', [u'Welcome to my', u'<strong>website</strong>'])
>>> il.add_value('price', [u'&euro;', u'<span>1000</span>'])
>>> il.load_item()
{'name': u'Welcome to my website', 'price': u'1000'}

入力プロセッサと出力プロセッサの両方の優先順位は次のとおりです:

  1. アイテムローダーのフィールド固有の属性: field_in および field_out (最優先)

  2. フィールド・メタデータ(input_processoroutput_processor キー)

  3. アイテム・ローダー デフォルト: ItemLoader.default_input_processor()ItemLoader.default_output_processor() (最も低い優先度)

アイテムローダーの再利用と拡張 も参照下さい。

アイテム・ローダー・コンテキスト

アイテムローダーコンテキストは、アイテムローダーのすべての入力プロセッサおよび出力プロセッサ間で共有される任意のキー・値ペアの辞書です。アイテム・ローダーの宣言、インスタンス化、または使用時に渡すことができます。これらは、入出力プロセッサの動作を変更するために使用されます。

たとえば、テキスト値を受け取り、そこから長さを抽出する parse_length 関数があるとします:

def parse_length(text, loader_context):
    unit = loader_context.get('unit', 'm')
    # ... length parsing code goes here ...
    return parsed_length

loader_context 引数を受け入れることにより、プロセッサ関数はアイテム・ローダーがアイテム・ローダー・コンテキストを受け取ることができることを明示的に伝えています。そのため、アイテム・ローダーはプロセッサ関数呼び出し時に現在アクティブなコンテキストを渡します。よってプロセッサ関数(この場合 parse_length)は現在アクティブなコンテキストを使用できます。

アイテムローダーのコンテキスト値を変更する方法はいくつかあります:

  1. 現在アクティブなアイテム・ローダー・コンテキスト( context 属性)を変更する:

    loader = ItemLoader(product)
    loader.context['unit'] = 'cm'
    
  2. アイテム・ローダーのインスタンス化時(アイテム・ローダー・コンストラクターのキーワード引数は、アイテム・ローダー・コンテキストに保存されます):

    loader = ItemLoader(product, unit='cm')
    
  3. アイテム・ローダーの宣言で、アイテム・ローダー・コンテキストを使用したインスタンス化をサポートする入出力プロセッサ用。 MapCompose はそれらの1つです:

    class ProductLoader(ItemLoader):
        length_out = MapCompose(parse_length, unit='cm')
    

ItemLoaderオブジェクト

class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)

指定されたアイテムを取り込むための新しいアイテムローダーを返します。 項目が指定されていない場合は、 default_item_class のクラスを使用して自動的にインスタンス化されます。

selector または response パラメーターでインスタンス化されると、 ItemLoader クラスは セレクター を使用してWebページからデータを抽出する便利なメカニズムを提供します。

パラメータ
  • item (Item object) -- add_xpath() または add_css() または add_value() への後続の呼び出しを使用して入力するアイテムインスタンス。

  • selector (Selector object) -- add_xpath() (代わりに add_css() ) または replace_xpath() (代わりに replace_css() )メソッドを使用する場合にデータを抽出するセレクター。

  • response (Response object) -- セレクター引数が指定されていない限り、 default_selector_class を使用してセレクターを構築するために使用されるレスポンス。この場合、この引数は無視されます。

アイテム、セレクター、レスポンス、および残りのキーワード引数はローダー・コンテキストに割り当てられます( context 属性からアクセス可能)。

ItemLoader インスタンスには以下のメソッドがあります:

get_value(value, *processors, **kwargs)

指定した processors とキーワード引数により、指定した value を処理します。

利用可能なキーワード引数:

パラメータ

re (str or compiled regex) -- プロセッサの前に適用される extract_regex() メソッドを使用して、指定された値からデータを抽出するために使用する正規表現

例:

>>> from scrapy.loader.processors import TakeFirst
>>> loader.get_value(u'name: foo', TakeFirst(), unicode.upper, re='name: (.+)')
'FOO`
add_value(field_name, value, *processors, **kwargs)

処理してから、指定したフィールドに指定した value を追加します。

値は、processorskwargs を与える事により、最初に get_value() を介して渡され、そして、 フィールド入力プロセッサ を通過し、そして、その結果は、そのフィールドで収集されたデータに追加されます。フィールドにすでに収集されたデータが含まれている場合、新しいデータが追加されます。

与える field_nameNone にすることができます。その場合、複数のフィールドの値が追加されます。 そして、処理された値は、field_nameが値にマッピングされた辞書でなければなりません。

例:

loader.add_value('name', u'Color TV')
loader.add_value('colours', [u'white', u'blue'])
loader.add_value('length', u'100')
loader.add_value('name', u'name: foo', TakeFirst(), re='name: (.+)')
loader.add_value(None, {'name': u'foo', 'sex': u'male'})
replace_value(field_name, value, *processors, **kwargs)

add_value() に似ていますが、収集したデータを追加する代わりに新しい値に置き換えます。

get_xpath(xpath, *processors, **kwargs)

ItemLoader.get_value() に似ていますが、値の代わりにXPathを受け取ります。これは、この ItemLoader に関連付けられたセレクターからUnicode文字列のリストを抽出するために使用されます。

パラメータ
  • xpath (str) -- データを抽出するためのXPath

  • re (str or compiled regex) -- 選択したXPath領域からデータを抽出するために使用する正規表現

例:

# HTML snippet: <p class="product-name">Color TV</p>
loader.get_xpath('//p[@class="product-name"]')
# HTML snippet: <p id="price">the price is $1200</p>
loader.get_xpath('//p[@id="price"]', TakeFirst(), re='the price is (.*)')
add_xpath(field_name, xpath, *processors, **kwargs)

ItemLoader.add_value() に似ていますが、値の代わりにXPathを受け取ります。これは、この ItemLoader に関連付けられたセレクターからUnicode文字列のリストを抽出するために使用されます。

kwargs については get_xpath() を参照してください。

パラメータ

xpath (str) -- データを抽出するためのXPath

例:

# HTML snippet: <p class="product-name">Color TV</p>
loader.add_xpath('name', '//p[@class="product-name"]')
# HTML snippet: <p id="price">the price is $1200</p>
loader.add_xpath('price', '//p[@id="price"]', re='the price is (.*)')
replace_xpath(field_name, xpath, *processors, **kwargs)

add_xpath() に似ていますが、収集したデータを追加する代わりに置き換えます。

get_css(css, *processors, **kwargs)

ItemLoader.get_value() に似ていますが、値の代わりにCSSセレクターを受け取ります。これは、この ItemLoader に関連付けられたセレクターからUnicode文字列のリストを抽出するために使用されます。

パラメータ
  • css (str) -- データを抽出するためのCSSセレクター

  • re (str or compiled regex) -- 選択したCSS領域からデータを抽出するために使用する正規表現

例:

# HTML snippet: <p class="product-name">Color TV</p>
loader.get_css('p.product-name')
# HTML snippet: <p id="price">the price is $1200</p>
loader.get_css('p#price', TakeFirst(), re='the price is (.*)')
add_css(field_name, css, *processors, **kwargs)

ItemLoader.add_value() に似ていますが、値の代わりにCSSセレクターを受け取ります。これは、この ItemLoader に関連付けられたセレクターからUnicode文字列のリストを抽出するために使用されます。

kwargs については get_css() を参照してください。

パラメータ

css (str) -- データを抽出するためのCSSセレクター

例:

# HTML snippet: <p class="product-name">Color TV</p>
loader.add_css('name', 'p.product-name')
# HTML snippet: <p id="price">the price is $1200</p>
loader.add_css('price', 'p#price', re='the price is (.*)')
replace_css(field_name, css, *processors, **kwargs)

add_css() に似ていますが、収集したデータを追加する代わりに置き換えます。

load_item()

これまでに収集されたデータをアイテムに入力し、それを返します。 収集されたデータは最初に 出力プロセッサ に渡され、各項目フィールドに割り当てる最終値を取得します。

nested_xpath(xpath)

xpathセレクターでネストされたローダーを作成します。 提供されたセレクターは、この ItemLoader に関連付けられたセレクターに対して相対的に適用されます。 ネストされたローダーは Item を親の ItemLoader と共有するため、 add_xpath()add_value()replace_value() などの呼び出しは期待どおりに動作します。

nested_css(css)

CSSセレクターでネストされたローダーを作成します。 提供されたセレクターは、この ItemLoader に関連付けられたセレクターに対して相対的に適用されます。 ネストされたローダーは Item を親の ItemLoader と共有するため、 add_xpath()add_value()replace_value() などの呼び出しは期待どおりに動作します。

get_collected_values(field_name)

指定のフィールドで収集された値を返します。

get_output_value(field_name)

指定されたフィールドについて、出力プロセッサを使用してパースされた収集値を返します。 このメソッドは、アイテムの入力や変更を一切行いません。

get_input_processor(field_name)

指定フィールドの入力プロセッサを返します。

get_output_processor(field_name)

指定フィールドの出力プロセッサを返します。

ItemLoader インスタンスには次の属性があります:

item

このアイテムローダーによってパースされる Item オブジェクト。

context

このアイテム・ローダーの現在アクティブな コンテキスト

default_item_class

コンストラクターで指定されていないときにアイテムをインスタンス化するために使用されるItemクラス(またはファクトリー)。

default_input_processor

入力プロセッサを指定しないフィールドに使用するデフォルトの入力プロセッサ。

default_output_processor

出力プロセッサを指定しないフィールドに使用するデフォルトの出力プロセッサ。

default_selector_class

コンストラクターでレスポンスのみが指定された場合、この ItemLoaderselector を構築するために使用されるクラス。コンストラクターでセレクターが指定されている場合、この属性は無視されます。 この属性はサブクラスでオーバーライドされる場合があります。

selector

データを抽出する Selector オブジェクト。 これは、コンストラクターで指定されたセレクター、またはコンストラクターで default_selector_class を使用して指定されたレスポンスから作成されたセレクターです。この属性は読み取り専用です。

ネストされたローダー

ドキュメントのサブセクションから関連する値をパースする場合、ネストされたローダーを作成すると便利です。以下のようなページのフッターから詳細を抽出しているとします:

例:

<footer>
    <a class="social" href="https://facebook.com/whatever">Like Us</a>
    <a class="social" href="https://twitter.com/whatever">Follow Us</a>
    <a class="email" href="mailto:whatever@example.com">Email Us</a>
</footer>

ネストされたローダーがない場合、あなたは抽出する値ごとに完全なxpath(またはcss)を指定する必要があります。

例:

loader = ItemLoader(item=Item())
# load stuff not in the footer
loader.add_xpath('social', '//footer/a[@class = "social"]/@href')
loader.add_xpath('email', '//footer/a[@class = "email"]/@href')
loader.load_item()

代わりに、あなたはフッター・セレクターを使用してネストされたローダーを作成し、フッターに関連する値を追加できます。機能は同じですが、あなたはフッター・セレクターの繰り返しを回避できます。

例:

loader = ItemLoader(item=Item())
# load stuff not in the footer
footer_loader = loader.nested_xpath('//footer')
footer_loader.add_xpath('social', 'a[@class = "social"]/@href')
footer_loader.add_xpath('email', 'a[@class = "email"]/@href')
# no need to call footer_loader.load_item()
loader.load_item()

あなたはローダーを任意にネストでき、xpathまたはcssセレクターで動作します。 一般的なガイドラインとして、ネストされたローダーを使用してコードを単純化します。ネストしないと、パーサーが読みにくくなる可能性があります。

アイテムローダーの再利用と拡張

あなたのプロジェクトが大きくなり、ますます多くのスパイダーを取得するにつれて、メンテナンスは根本的な問題になります。特に、各スパイダーの多くの異なるパースルールを処理する必要がある場合、多くの例外があります。また、共通のプロセッサを再利用したい場合も同様です。

アイテムローダーは、柔軟性を失うことなく、パースルールのメンテナンスの負担を軽減するように設計されていると同時に、それらを拡張およびオーバーライドするための便利なメカニズムを提供します。このため、アイテムローダーは、特定のスパイダー(またはスパイダーのグループ)の違いを処理するために、従来のPythonクラスの継承をサポートしています。

たとえば、ある特定のサイトが製品名を3つのダッシュ(たとえば ---Plasma TV--- )で囲んでおり、最終製品名でそれらのダッシュをスクレイピングしたくないと仮定します。

ここで、デフォルトの製品アイテムローダー( ProductLoader )を再利用して拡張することで、これらのダッシュを削除する方法を次に示します:

from scrapy.loader.processors import MapCompose
from myproject.ItemLoaders import ProductLoader

def strip_dashes(x):
    return x.strip('-')

class SiteSpecificLoader(ProductLoader):
    name_in = MapCompose(strip_dashes, ProductLoader.name_in)

アイテムローダーの拡張が非常に役立つ別のケースは、XMLやHTMLなどの複数のソース形式がある場合です。XMLバージョンでは、 CDATA の出現を削除することができます。方法の例を次に示します:

from scrapy.loader.processors import MapCompose
from myproject.ItemLoaders import ProductLoader
from myproject.utils.xml import remove_cdata

class XmlProductLoader(ProductLoader):
    name_in = MapCompose(remove_cdata, ProductLoader.name_in)

そして、それは、入力プロセッサを拡張する典型的な方法です。

出力プロセッサについては、フィールドメタデータで宣言する方が一般的です。これは、通常、(入力プロセッサのように)特定の各サイトのパースルールではなく、フィールドのみに依存するためです。 入力プロセッサと出力プロセッサの宣言 も参照してください。

アイテムローダーを拡張、継承、およびオーバーライドする方法は他にもたくさんあります。さまざまなアイテムローダーの階層は、さまざまなプロジェクトにより適しています。 Scrapyはメカニズムのみを提供します。 ローダーコレクションの特定の構成を強制することはありません。それはあなたとプロジェクトのニーズ次第です。

利用可能な組み込みプロセッサ

呼び出し可能な関数を入力プロセッサおよび出力プロセッサとして使用できますが、Scrapyは一般的に使用されるいくつかのプロセッサを提供します。これらについては以下で説明します。 MapCompose (通常は入力プロセッサとして使用される)のようなそれらのいくつかは、最終的にパースされた値を生成するために、順番に実行されるいくつかの関数の出力を構成します。

以下に、すべての組み込みプロセッサのリストがあります:

class scrapy.loader.processors.Identity

何もしない最も単純なプロセッサ。元の値を変更せずに返します。コンストラクター引数を受け取らず、ローダーコンテキストも受け入れません。

例:

>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['one', 'two', 'three'])
['one', 'two', 'three']
class scrapy.loader.processors.TakeFirst

受信した値から最初の非ヌル/空でない(non-null/non-empty)値を返します。したがって、通常は単一値フィールドへの出力プロセッサとして使用されます。コンストラクター引数を受け取らず、ローダーコンテキストも受け入れません。

例:

>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'one', 'two', 'three'])
'one'
class scrapy.loader.processors.Join(separator=u' ')

コンストラクタで指定されたセパレータで結合した返します。セパレータのデフォルトは u' ' (空白1文字)です。ローダーコンテキストは受け入れません。

デフォルトのセパレータを使用する場合、このプロセッサは次の関数と同等です: u' '.join

例:

>>> from scrapy.loader.processors import Join
>>> proc = Join()
>>> proc(['one', 'two', 'three'])
'one two three'
>>> proc = Join('<br>')
>>> proc(['one', 'two', 'three'])
'one<br>two<br>three'
class scrapy.loader.processors.Compose(*functions, **default_loader_context)

与えた関数(達)の組み合わせで構築されたプロセッサー。つまり、このプロセッサの各入力値は最初の関数に渡され、その関数の結果は2番目の関数に渡され、最後の関数がこのプロセッサの出力値を返すまで続きます。

デフォルトでは、 None の値で処理を停止します。この動作は、キーワード引数 stop_on_none = False を渡すことで変更できます。

例:

>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)
>>> proc(['hello', 'world'])
'HELLO'

各関数はオプションで loader_context パラメーターを受け取ることができます。実行する場合、このプロセッサーは現在アクティブな ローダー・コンテキスト をそのパラメーターを通して渡します。

コンストラクターに渡されるキーワード引数は、各関数呼び出しに渡されるデフォルトのローダーコンテキスト値として使用されます。 ただし、関数に渡される最終的なローダーコンテキスト値は、 ItemLoader.context() 属性を介してアクセス可能な、現在アクティブなローダーコンテキストでオーバーライドされます。

class scrapy.loader.processors.MapCompose(*functions, **default_loader_context)

Compose プロセッサと同様に、指定された関数の組み合わせから構築されるプロセッサ。このプロセッサーとの違いは、内部結果が関数間で渡される方法です。これは次のとおりです:

このプロセッサの入力値は 反復可能 であり、最初の関数が各要素に適用されます。これらの関数呼び出しの結果(要素ごとに1つ)が連結されて新しい反復可能要素が作成され、2番目の関数の適用に使用されます。収集された値のリストの各値に最後の関数が適用されるまで、それが延々続きます。最後の関数の出力値が連結されて、このプロセッサーの出力が生成されます。

特定の各関数は、値または値のリストを返すことができます。これは、他の入力値に適用された同じ関数によって返される値のリストでフラット化されます。関数は None を返すこともできます。その場合、その関数の出力は無視され、以後の関数チェーンでのさらなる処理が行われます。

このプロセッサは、(反復可能要素の代わりに、)単一の値でのみ機能する関数を構成する便利な方法を提供します。このため、データはしばしば セレクターextract() メソッドを使用して抽出され、そのため、通常は MapCompose プロセッサが入力プロセッサとして使用されます。Unicode文字列のリストを返します。

以下の例は、それがどのように機能するかを明確にするはずです:

>>> def filter_world(x):
...     return None if x == 'world' else x
...
>>> from scrapy.loader.processors import MapCompose
>>> proc = MapCompose(filter_world, str.upper)
>>> proc(['hello', 'world', 'this', 'is', 'scrapy'])
['HELLO, 'THIS', 'IS', 'SCRAPY']

Composeプロセッサと同様に、関数はローダーコンテキストを受け取ることができ、コンストラクターのキーワード引数はデフォルトのコンテキスト値として使用されます。 詳細については、 Compose プロセッサを参照してください。

class scrapy.loader.processors.SelectJmes(json_path)

コンストラクターに提供されたjsonパスを使用して値を照会し、出力を返します。 実行するにはjmespath(https://github.com/jmespath/jmespath.py)が必要です。このプロセッサは、一度に1つの入力のみを受け取ります。

例:

>>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose
>>> proc = SelectJmes("foo") #for direct use on lists and dictionaries
>>> proc({'foo': 'bar'})
'bar'
>>> proc({'foo': {'bar': 'baz'}})
{'bar': 'baz'}

Jsonの操作:

>>> import json
>>> proc_single_json_str = Compose(json.loads, SelectJmes("foo"))
>>> proc_single_json_str('{"foo": "bar"}')
'bar'
>>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('foo')))
>>> proc_json_list('[{"foo":"bar"}, {"baz":"tar"}]')
['bar']