Scrapyを時刻起動させられるデーモン、scrapy-doを試してみたので、記録しておきます。
ネット上に情報が少ないこともあり、少しでも貢献できれば幸いです。
環境情報
Python 3.7.7
Scrapy 2.1.0
scrapy-do 0.4.0
macOS Catalina 10.15.4
scrapy-doについて
scrapy-doはLukasz Janyst氏が開発するScrapyの実行用デーモンです。
Scrapyのジョブを管理するコマンドライン、REST API、WebGUIが備わっています。
(公式ドキュメントはこちら)
Scrapyの実行デーモンとしては、scrapydが有名ですが、scrapy-doはscrapydにインスパイアされて開発したとのことです。
どちらも常駐プロセスとしてScrapyを実行しますが、scrapy-doは起動タイミングや実行間隔を持つ点がscrapydと大きく異なります。
scrapydでスケジュール管理をする時はcronやその他スケジューラを併用することになりますが、scrapy-doはジョブの登録時に「毎日t時に起動」のような指定が可能です。
早速使ってみる
前提事項
Scrapyチュートリアルのquotes_spider
の一部を題材にします。
インストール
pipでscrapy-doをインストールします。
pip install scrapy-do
起動
任意のディレクトリで起動します。
scrapy-do -n scrapy-do
起動したディレクトリに projects
というディレクトリが作成されます。
実行ログやスケジュール情報が置かれる場所です。
projects
├── spider-data
├── schedule.db
├── metadata.pkl
└── log-dir
実行環境設定
ジョブ実行の並列数やプロジェクトの保存先など、設定全般は設定ファイルで指定します。
詳細は公式ドキュメントServer Configurationを参照。
scrapy-do scrapy-do --config /path/to/config/file.conf
プロジェクトのpush(コマンド)
Scrapyプロジェクトをpushします。
ここでいうプロジェクトとは、scrapy startproject tutorial
のtutorial
を意味しています。
pushの方法はcliとRESTの2通り。
まずはcliでpushしてみます。
デフォルトでカレントディレクトリのプロジェクトをpushしますが、--project-path
でpush対象のパスを指定することも可能です。
cd tutorial
scrapy-do-cl push-project
+------------+
| tutorial |
|------------|
| quotes |
+------------+
pushすると、プロジェクト内にあるスパイダーを見つけて表示してくれます。
さきほどのprojectsディレクトリを見てみると、pushされたtutorialプロジェクトが追加されているのがわかります。
projects
├── [ 64] log-dir
├── [ 140] metadata.pkl
├── [ 20K] schedule.db
├── [ 64] spider-data
└── [9.1K] tutorial.zip
なお、scrapy-doではスパイダーを更新した時はプロジェクトの再pushが必要です。
再pushと初回pushで実行方法に違いはありません。
プロジェクトのpush(REST)
一応RESTでpushする場合も試してみます。
RESTでpushするときは、push対象のプロジェクトをzip圧縮してパラメータで指定します。
zip -r tutorial_archive.zip tutorial/
curl -s http://localhost:7654/push-project.json \
-F archive=@tutorial_archive.zip | jq -r
{
"status": "ok",
"name": "tutorial",
"spiders": [
"quotes"
]
}
サーバ側のコンソールにはプロジェクトの受付ログが出力されています。
2020-05-24T10:12:14+0900 [scrapy_do.controller.Controller#info] Pushing new project
2020-05-24T10:12:15+0900 [scrapy_do.controller.Controller#info] Added project "tutorial" with spiders ['quotes']
2020-05-24T10:12:15+0900 [twisted.python.log#info] "127.0.0.1" - - [24/May/2020:01:12:14 +0000] "POST /push-project.json HTTP/1.1" 200 60 "-" "python-requests/2.23.0"
ジョブのスケジューリング
ジョブの実行をスケジューリングしてみます。
特徴的なのが--when
で指定する起動タイミング。
結構オシャレな指定方法になってます。
詳しくは公式ドキュメントのScheduling Specsを参照
- 'every monday at 12:30'
- 'every 2 to 3 hours'
- 'every 6 minutes'
- 'every hour at 00:15'
scrapy-do-cl schedule-job --project tutorial \
--spider quotes --when 'every 3 minutes'
+--------------------------------------+
| identifier |
|--------------------------------------|
| 3280bfb3-01df-49a5-aa53-805a5723df93 |
+--------------------------------------+
即時実行させたい時は --when 'now'
と指定します。
ジョブのキャンセル
登録したジョブをキャンセルしたい時は、cancel-jobコマンド or APIでジョブIDを指定します。
scrapy-do-cl cancel-job --job-id 3280bfb3-01df-49a5-aa53-805a5723df93
Canceled.
ジョブの結果確認
ジョブの実行状況は、確認コマンド or APIで確認できます。
ステータスACTIVE
で実行中ジョブ、COMPLETED
で終了したジョブを確認できます。
curl -s "http://localhost:7654/list-jobs.json?status=ACTIVE" | jq -r
{
"status": "ok",
"jobs": [
{
"identifier": "ddd118dd-15f0-4448-8408-967fc806a859",
"status": "SUCCESSFUL",
"actor": "USER",
"schedule": "now",
"project": "tutorial",
"spider": "quotes",
"description": "",
"timestamp": "2020-05-24 14:14:34.990209",
"duration": 3,
"payload": "{\"testkey\": \"hogehoge\"}"
},
...
若干(というか結構)気になったのが、--when 'every 3 minutes'
で指定したジョブは、実際に実行される時に別ジョブIDが発行されて、結果を見ると"schedule": "now"
で実行されたことになっている点。
時刻が来ると--when 'now'
で即時ジョブを登録するようになっているみたいです。
Spiderに引数を渡す
スケジューリングの際にpayload
オプションを指定すると、Spiderに引数を渡せます。
指定できるのはvalidなJSON形式に限られており、Spider側からはpayload
という引数名で受け取ることができます。
curl -s http://localhost:7654/schedule-job.json \
-F project=tutorial \
-F spider=quotes \
-F "when=now" \
-F payload='{"hoge": "foobar"}' | jq -r
引数はJSON形式のstringで渡ってくるので、astなどで辞書型に変換して使います。
Web GUI
ここまで書いてきませんでしたが、localhost:7654
でアクセスできる管理画面も提供されています。
ただ私の環境が悪いのか、ジョブを登録した後に画面を開くと、JavaScriptのシンタックスエラーが発生して見えなくなってしまいました。
さいごに
scrapy-doを軽く動かしてみました。
まだバージョンは0.4.0ですが、scrapydで悩ましかった時刻起動がカバーされているのは非常にありがたく、今後に期待したいと思います。