Scrapy - Spiderに渡す引数は初期化の省略が可能

# 結論
ScrapyのSpiderに渡す引数(Argument: -a )について、初期化が推奨されています。
初期化は、他のライブラリ同様に「\_\_init\_\_」関数内にて行うのが一般的です。

以下のサンプルプログラムでは、
`def __init__(self, feed=None, *args, **kwargs):`のメソッド引数 feed=Noneで初期化されています。
しかし、これは必須ではありませんでした。
そのためには、feedではなく、**self.feed**としてクラス変数で参照する必要があります。
(Scrapy 2.5.0で検証)

> 公式ドキュメントより引用
> The default \_\_init\_\_ method will take any spider arguments and copy them to the spider as attributes. 

\_\_init\_\_がデフォルトでspiderの全ての引数を受け取り、インスタンスの属性としてそのspiderにコピーするためです。

## 経緯
Spiderに渡す引数の取り扱いにて少しわかりにくいところがあったので残します。
公式のチュートリアルでも「\_\_init\_\_」関数内で受け取る引数には初期化がついていましたが、self.で参照すれば明示的な初期化の記述がなくても動作しましたので備忘録として。

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

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

```python: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はself.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関数のfeed=Noneを省略しても動作します。

```python: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': []}

feed変数を初期化しない影響としては、引数にfeed値を与えずに実行した際にAttributeエラーが発生します。
>% scrapy crawl test_argument_spider -a message="hogehoge"  
`AttributeError: 'TestArgumentSpiderSpider' object has no attribute 'feed'`

### 別解2 (追記)
```python:test_argument_spider_init3.py
import scrapy

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

    def start_requests(self):
        print(vars(self))
        yield scrapy.Request(f'http://qiita.com/{self.feed}')

    def parse(self, response):
        args_message = self.message
        
        pass
```
print文の出力
> {'feed': 'trend', 'message': 'hogehoge', 'start_urls': [], 'crawler': <scrapy.crawler.Crawler object at 0x10b789df0>, 'settings': <scrapy.settings.Settings object at 0x10b789820>}

同様に、引数にfeed値を与えずに実行した際にAttributeエラーが発生します。

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

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

*参考リンク*
[公式ドキュメントの該当箇所](https://docs.scrapy.org/en/latest/topics/spiders.html?highlight=__init__(*args%2C%20**kwargs)#spider-arguments)
[公開ソースコードの該当箇所](https://github.com/scrapy/scrapy/blob/master/scrapy/spiders/crawl.py#L66)