今回は、前回で「Yahoo!ニューススクレイピングをgoogleスプレッドシートに連携」をローカルで自動実行してみたいと思います。
自動実行にはcrontabを使います。
crontabを使えば、定期的にコマンドが実行できます。分、時、日、月、曜日で細かくスケジュールが設定できます。
crontabの使い方
主なオプション
オプション | 説明 |
---|---|
-e | 編集。エディターが立ち上がってcrontabを編集できます。 |
-l | 現在のcrontabを標準出力に表示します。 |
-r | 現在のcrontabを削除します。 |
crontabのフィールド
crontabのフィールドは、分、時、日、月、曜日の5種類があり、最後に起動したい処理を記述します。
# cronの起動時間設定
* * * * * (起動したい処理)
# | | | | |
# | | | | |- 曜日 day of week 0-7 (0 or 7 is Sunday, or use names example:"mon,wed,fri)
# | | | |--- 月 month 1-12 (or names example:"jan-mar")
# | | |----- 日 day of month 1-31
# | |------- 時 hour 0-23
# |--------- 分 minute 0-59
crontabの設定サンプル
以下、crontabの設定サンプルです。
* * * * * (起動したい処理) # 毎分起動する
*/3 * * * * (起動したい処理) # 3分ごとに起動する
20 * * * * (起動したい処理) # 毎時20分
10,30 * * * * (起動したい処理) # 毎時10分と30分(カンマ指定)
0-10 * * * * (起動したい処理) # 毎時00〜10分に、1分毎に起動(ハイフン指定)
1 3 * * * (起動したい処理) # 毎日3時01分
0 1,3 * * * (起動したい処理) # 毎日1時と3時に、00分に起動(カンマ指定)
0 1-6 * * * (起動したい処理) # 毎日1時〜6時まで、00分に起動(ハイフン指定)
0 */2 * * * (起動したい処理) # 2時間ごとに起動する(0時、2時、4時、...)
# 0:sun 1:mon 2:tue 3:wed 4:thu 5:fri 6:sat 7:sun
0 9 * * 0 (起動したい処理) # 毎週日曜日の午前9:00に起動
0 9 * * 1,3 (起動したい処理) # 毎週月,水曜日の午前9:00に起動(カンマ指定)
0 9 * * 1-5 (起動したい処理) # 毎週月〜金曜日の午前9:00に起動(ハイフン指定)
10 4 1 * * (起動したい処理) # 毎月1日の4:10に起動
10 4 3,13 * * (起動したい処理) # 毎月3日と13日の、4:10に起動(カンマ指定)
10 4 3-5 * * (起動したい処理) # 毎月3〜5日の4:10に起動(ハイフン指定)
0 10 3 1 * (起動したい処理) # 毎年1月3日の10:00に起動
(起動したい処理)の設定
次に、(起動したい処理)の設定の仕方について見ていきます。
まず、cronが動いた時間を記録するPGMを作ってテストします。
from datetime import datetime
datetimestr = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
print(datetimestr,'cronが動いた!')
このPGMを動かすために、通常、普通にpyがあるディレクトリに移動して、pythonを実行する時は、以下のような感じですね。
% python cron-test.py
これをこのまま(起動したい処理)に記載してみます。
加えて、logはリダイレクトします。(logはユーザーのホームディレクトりに作られます。)
* * * * * python cron-test.py >> cron-test.log 2>&1
/bin/sh: Applications: command not found
動きません。留意すべき落とし穴が3つあります。
①当該のディレクトリにあらかじめ移動しないと、うまく動かない。
②パスはフルパスでないと認識しない。
③cron独自にもつPATH環境変数がデフォルトだと、うまく動かない。
①当該のディレクトリにあらかじめ移動しないと、うまく動かない。
そもそもホームディレクトリで動こうとするみたいなので、正しいディレクトリに移動してから、動かしてみます。
通常コマンドと同様に、cdで実行ディレクトリに移動。;で区切ってpythonコマンドを指定します。
* * * * * cd /Users/inoken/git-repository/env2; python cron-test.py >> cron-test.log 2>&1
python: can't open file 'cron-test.py': [Errno 2] No such file or directory
エラーは変わりますが、動きません。
②パスはフルパスでないと認識しない。
パスはとにかくフルパスでないと受け付けないようです。
とりあえず、pythonとpyファイルのフルパスを確認します。
% which python
/Users/inoken/git-repository/env2/env2/bin/python
% pwd
/Users/inoken/git-repository/env2
% ls -la | grep cron
-rw-r--r-- 1 inoken staff 131 9 19 17:46 cron-test.py
ディレクトリ移動した上で、さらにフルパス指定します。
* * * * * cd /Users/inoken/git-repository/env2; /Users/inoken/git-repository/env2/bin/python /Users/inoken/git-repository/env2/cron-test.py >> cron-test.log 2>&1
/bin/sh: Applications: command not found
まだダメです。
ちなみにディレクトリ移動せず、pythonとpyファイルをフルパスにしても、同様に動きません。
* * * * * /Users/inoken/git-repository/env2/bin/python /Users/inoken/git-repository/env2/cron-test.py >> cron-test.log 2>&1
/bin/sh: Applications: command not found
③cron独自にもつPATH環境変数がデフォルトだと、うまく動かない。
cronのenvを出力してみます。
* * * * * cd /Users/inoken/git-repository/env2; env > cron.log 2>&1
cdしてもPWDは変わってないのは不思議ですが、PATHが/usr/bin:/binにしか通っていません。
% cat ~/cron.log
SHELL=/bin/sh
USER=inoken
PATH=/usr/bin:/bin
PWD=/Users/inoken
SHLVL=1
HOME=/Users/inoken
LOGNAME=inoken
_=/usr/bin/env
ですので、PATHに少なくともpythonのパスを通します。
venv環境の環境変数を確認して、丸ごとパクります。
% echo $PATH
/Users/inoken/git-repository/env2/env2/bin:/Users/inoken/google-cloud-sdk/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Users/inoken/google-cloud-sdk/bin
そして、先頭にPATHを指定した後、サイクルとコマンドを指定します。
PATH=/Users/inoken/git-repository/env2/env2/bin:/Users/inoken/google-cloud-sdk/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Users/inoken/google-cloud-sdk/bin
* * * * * cd /Users/inoken/git-repository/env2; /Users/inoken/git-repository/env2/bin/python /Users/inoken/git-repository/env2/cron-test.py >> cron-test.log 2>&1
長くて死にそうですが、仕方ありません。
PATHが塗り変わってくれて、ようやく無事動きました。
SHELL=/bin/sh
USER=inoken
PATH=/Users/inoken/git-repository/env2/env2/bin:/Users/inoken/google-cloud-sdk/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Users/inoken/google-cloud-sdk/bin
PWD=/Users/inoken
SHLVL=1
HOME=/Users/inoken
LOGNAME=inoken
_=/usr/bin/env
% cat ~/cron-test.log
2020/09/19 21:49:01 cronが動いた!
2020/09/19 21:50:00 cronが動いた!
2020/09/19 21:51:00 cronが動いた!
crontabでスプレイピングを自動実行
いよいよ本題。
スクレイピングのPGMを動かします。
と言っても、先ほどのテストpyファイル名を塗り替えるだけです。(log名は適宜。)
* * * * * cd /Users/inoken/git-repository/env2; /Users/inoken/git-repository/env2/bin/python /Users/inoken/git-repository/env2/requests-test2.py >> /Users/inoken/log/cron3h.log 2>&1
2020/09/19 17:37:51 スクレイピングを終了しました。
無事、自動実行に成功しました。
自動実行の課題
自動実行は成功しましたが、さらに難題があります。
④MacBookスリープ中は動かない。
ずっとスリープさせないのも無駄ですし、
他に何か方法はあるのかもしれませんが、難易度は高いでしょう。
1分おきや3分おきはテストは以下のようにできたとしても、それ以上大きいサイクルなどはスリープしてしまうと動かすことができません。
1分おき
% cat /Users/inoken/log/cron-test.log
2020/09/19 17:50:01 cronが動いた!
2020/09/19 17:51:00 cronが動いた!
2020/09/19 17:52:00 cronが動いた!
2020/09/19 17:53:00 cronが動いた!
3分おき
% cat /Users/inoken/log/cron-test.log
2020/09/19 19:12:01 cronが動いた!
2020/09/19 19:15:00 cronが動いた!
2020/09/19 19:18:00 cronが動いた!
1日1回なら定期的にやる方法あり
ただ、1日1回なら定期的にやる方法はあります。
Macのシステム環境設定 > 省エネルギー > スケジュール で、
毎日のスリープ解除の時間を設定することができます。
このスリープ解除されている時間帯にすかさずcrontabの時間を合わせて自動実行を行えば、一応実行は可能です。(スリープの設定によっては、またすぐスリープするので、夜中3:00にスリープ解除して、3:01に自動実行する、などすかさず自動実行すると良いです。)
1 3 * * * cd /Users/inoken/git-repository/env2; /Users/inoken/git-repository/env2/bin/python /Users/inoken/git-repository/env2/requests-test2.py >> /Users/inoken/log/cron3h.log 2>&1
% cat /Users/inoken/log/cron3h.log
2020/09/20 03:01:29 スクレイピングを終了しました。
まとめ
Macでのcrontab実行にあたっての注意点
①当該のディレクトリにあらかじめ移動しないと、うまく動かない。
②パスはフルパスでないと認識しない。
③cron独自にもつPATH環境変数がデフォルトだと、うまく動かない。
④MacBookさんスリープ中は動かない。
参考サイト