Scrapy - Spiderに渡す引数のうち__init__関数内で利用するものでも初期化宣言が必須ではなかった


結論

ScrapyのSpiderに渡す引数(Argument)は「__init__」関数内で利用するものは初期化宣言が引数の渡し忘れに備えて推奨されています。
以下のサンプルプログラムでいう、feedはdef __init__(self, feed=None, *args, **kwargs):にてfeed=Noneが初期化宣言です。検証した結果、これがなくても動作でき必須ではありませんでした。ただしself.feedとしてクラス変数を参照する必要があります。
(Scrapy 2.5.0で検証)

経緯

Spiderに渡す引数の取り扱いにわかりにくいところがあったので残します。
公式のチュートリアルでも「__init__」関数内で受け取る引数には初期化宣言がついているのですが、
これが他のインスタンス関数では不要で場合分けが必要だと思ったので調べました。

検証

qiita.comのfeed部分と任意messageがSpiderの引数になっているサンプルプログラムを例にします。
レスポンスのparse部分やmiddleware, pipeline処理は割愛しています。

実行コマンド例
% scrapy crawl test_argument_spider -a feed="trend" -a message="hogehoge"

test_argument_spider.py
import scrapy

class TestArgumentSpiderSpider(scrapy.Spider):
    name = 'test_argument_spider'
    allowed_domains = ['qiita.com']

    def __init__(self, feed=None, *args, **kwargs):
        super(TestArgumentSpiderSpider, self).__init__(*args, **kwargs) #引数を受け取るための継承
        self.start_urls = [f'http://qiita.com/{feed}'] #クラス変数に格納するためself.start_urlsとselfを付ける
        # ...

    def parse(self, response):
        args_message = self.message #引数 messageは__init__で初期化されなくても橋渡しされている
        print(vars(self))
        pass

parse関数のprint文の出力

{'message': 'hogehoge', 'start_urls': ['http://qiita.com/trend'], 'crawler': <scrapy.crawler.Crawler object at 0x107f3ddf0>, 'settings': <scrapy.settings.Settings object at 0x107f3d940>}

渡された引数を__init__関数で初期化することは必須ではなく、self.feedとして__init__関数で利用できました。
上記init関数を以下のようにに変更しても動作します。

test_argument_spider_init2.py
    def __init__(self, *args, **kwargs):
        super(TestArgumentSpiderSpider, self).__init__(*args, **kwargs)
        print(vars(self))
        self.start_urls = [f'http://qiita.com/{self.feed}']

print文の出力

{'feed': 'trend', 'message': 'hogehoge', 'start_urls': []}

crawlerインスタンスが作成される前に引数がsuper(TestArgumentSpiderSpider, self).__init__(*args, **kwargs)の継承によって橋渡しされています。

この場合のfeed変数を初期化しない影響としては、引数にfeed値を与えずに実行した際にAttributeエラーが発生します。

% scrapy crawl test_argument_spider -a message="hogehoge"

AttributeError: 'TestArgumentSpiderSpider' object has no attribute 'feed'


変数は初期化することが推奨されているので、前者を参考にSpiderを構築した方が良いですが、
動的に引数を与えていくようなSpiderの場合は、あえてエラーを出すという選択肢があるかもしれません。
その場合は、後者が参考になれば幸いです。

以上、ScrapyにおけるSpiderへの引数格納のタイミングと初期化の検証でした。

参考リンク
公式ドキュメントの該当箇所
公開ソースコードの該当箇所