軽めのスクレイピングプラットフォームを求めてScrapydを試してみた

# Scrapydというものがあるらしい

日本語の記事としてはググってみると”[クローラーをデーモンとして動かす ― Scrapyd](http://orangain.hatenablog.com/entry/scrapyd)”などの記事が見つかった。

Scrapyをデーモンとして動かせるということだったので、これは”[我が家のZaimデータを描画する基盤を作った](https://qiita.com/inTheRye/items/cd8a596af860bd649574)”の記事の、airflowを使ったプラットフォームを、scrapy化してもっと軽い形で実現できるかもしれないと期待して試してみた。

# 何はともあれScrapydが動くdockerコンテナ作成

"scrapyd docker"とかでググってみると、幾つかscrapydのdockerコンテナが見つかる。

基本的に、pythonが入っていれば`$ pip install scrapyd`でインストール可能のようなので、1からdockerイメージを作ってもよかったけど、今回はalpine linuxベースで作られた[harrisbaird/scrapyd](https://hub.docker.com/r/harrisbaird/scrapyd/)のdockerイメージをベースに使わせてもらうことにした。

ここで、[Scrapyを使って人工衛星の軌道情報をスクレイピングしてみた](https://qiita.com/inTheRye/items/ec49fc1c4e888f935b2b)の記事で作ったspiderを動かすために、以下のようなdocker-compose用ファイル群を収めたgithubリポジトリを作成した。

https://github.com/inTheRye/docker-scrapyd

# Scrapydコンテナの設定

上記githubリポジトリの[scrapyd.conf](https://github.com/inTheRye/docker-scrapyd/blob/master/scrapyd/config/scrapyd.conf)にて、設定を行っているものは基本的には、[公式ドキュメント](http://scrapyd.readthedocs.io/en/stable/config.html#example-configuration-file)にある設定を踏襲している。

異なる点は、`bind_address = 0.0.0.0`としている点のみ。これは、このScrapydへのアクセスを全てのネットワークから許可する設定になっている。そのため、インターネット上でアクセスできる場所などでコンテナを立ち上げると、あらゆるネットワークからアクセスできてしまうので、注意が必要。

上記の設定はdockerコンテナでport forwardしていると、`bind_address = 127.0.0.1`の設定では、ホストマシンのlocalhostからアクセスしていても接続できなかったため上記のように修正した。

# Scrapydコンテナの立ち上げ

上記のリポジトリにもあるように

```bash
$ git clone https://github.com/inTheRye/docker-scrapyd.git
$ cd docker-scrapyd
$ docker-compose up -d
```

でコンテナを立ち上げる。

# Scrapydコンテナへのアクセス

http://localhost:6800/

でアクセスすると以下のようなtop画面が表示される。

![scrapyd_top.png](https://qiita-image-store.s3.amazonaws.com/0/32853/875da747-7f5a-d79d-d040-899c11adf2fa.png)

# Scrapydへ自作Spiderの登録

[公式ドキュメント](http://scrapyd.readthedocs.io/en/stable/deploy.html)にあるように、jsonのendpointにhttpアクセスするか、[scrapyd-client](https://github.com/scrapy/scrapyd-client)をインストールして、spiderをscrapyd上にデプロイするかどちらかの方法があるようだった。
（scrapyd-clientもおそらく上記、httpリクエストによるアクセスをラップしているだけと思われるがこちらの方が楽）

```bash
$ pip install git+https://github.com/scrapy/scrapyd-client
```

でscraped-clientをインストールする。

[Scrapyを使って人工衛星の軌道情報をスクレイピングしてみた](https://qiita.com/inTheRye/items/ec49fc1c4e888f935b2b)の記事にある、`scrapy-sample-baseball/space_object`のディレクトリ直下にある`scrapy.cfg`のdeploy先のurlのコメントアウトを解除する。

```
[deploy]
url = http://192.168.1.2:6800/
```

`scrapy-sample-baseball/space_object`のディレクトリ直下で、以下のコマンドを実行。

```bash
$ scrapyd-deploy
```

これで、scrapydにspiderが登録できる。

# 登録されたSpiderの実行

`scrapy-sample-baseball/space_object`のディレクトリ直下で、以下のコマンドを実行。

```bash
$ scrapyd-client schedule -p space_object tle 
```

top画面から、"Jobs"のリンクをクリックすると

![scrapyd_jobs.png](https://qiita-image-store.s3.amazonaws.com/0/32853/8f680489-85d3-96a9-731e-371085c1f47a.png)

のような形でSpiderのスクレイピングジョブが走っていることが確認できる。

## Spider実行時の注意事項

今回、scrapydでの実行にあたり、spiderクラスのコンストラクタを以下のような多引数を受け取れるようなものに修正した。

```python3:space_object/spiders/tle.py
    def __init__(self, *args, **kwargs):
```

[Error with Spider arguments sent using Scrapyd](https://github.com/scrapy/scrapyd/issues/78)にあるように、scrapydでの実行では_jobのキーワード引数をspiderに送っているようで、上記のようにしておかないとエラーになる。

# Scrapydを試してみて

## 良さそうな点

貧弱な計算リソースしか確保できない我が家では悪くないなと思った。ただし、scheduleと言っていながら、実際のスケジューリング機能などは無いようなので、スケジューリング自体はcronなどで自前で設定する必要がある。

ジョブ実行のログ取得は自前で考えるよりも楽ができる。

また、我が家ではあんまり関係無いが、複数のspiderを実行する時などはある程度Scrapydが、並列実行含めてよしなに実行してくれそうなので、その点も良さそうだ。（airflow[celery]での並列実行ほどのものは求めていないのでこの程度の軽さで良い）

## なんとなく気持ち悪い点

良さそうな点はあるのだが、一番気持ち悪いのは上記を実行しようとするとScrapydのコンテナとScrapyプロジェクトを収めたコンテナを用意して、httpインタフェースを介してjob実行するために、Scrapyプロジェクトのコンテナでcronで定期スケジュールする必要がある。

これだと、双方のコンテナでほとんど同じpythonのモジュールをimportしておかなければならず役割分担としては重複が多く微妙になる。ではscrapydコンテナとscrapyプロジェクトのコンテナをまとめてしまってはどうかと言うと、同じコンテナ内でジョブ実行のためにhttpインタフェースを介して通信するというのはなんとなく気持ち悪いなと思ってしまった。