Pythonの定期的実行:Cronとscheduleモジュール

Cron

cron(crontab)とは、ジョブ管理コマンドで、指定された日時、もしくは時間間隔でジョブを実行する。実行されるジョブは、crontab(cron table)でスケジュールされる。
このcrontabには、cronジョブのスケジュールが書き込まれ、その書式は以下のようになる。

* * * * * echo ‘Hello’ >> /tmp/test.txt

最初の5つの$${*}$$は実行時間日時で、この後にコマンドをかく。
cronジョブの実行に関してのユーザー制限は、
/usr/lib/cron/cron.deny
/usr/lib/cron/cron.allow
で、制御される。このファイルの持ち主は当然ながらrootである。

crontab コマンド

crontabのファイルの記述は

%crontab -e

で行う。記述形式はvi仕様である。
実行中のcronジョブの一覧と中身は、

% crontab -l  
* * * * * echo ‘Hello’ >> /tmp/test.txt

で確認できる。
cronジョブの停止、crontabの削除は

% crontab -r

で行われる。ただし、cronは毎分crontabの変更を確認し、変更されたものを実行するため、crontabの中身を変更しても再起動は必要ない。
crontabのジョブ指定には、crontab -eで直接書き込む方法のほかに、スクリプトで指定することも可能である。

% cat ./script.sh
* * * * *  echo ‘Hello’  >> /tmp/test.txt
% crontab < ./script.sh

crontab syntaxs

crontabの時間指定は以下のようになっている。

* * * * * echo ‘Hello’ >> /tmp/test.txt
| | | | |
| | | | days of week(0-6) 0:sunday
| | | month(1-12)
| | day of the month(1-31)
| hour(0-23)
min(0-59)

毎日の午後6時半に、/home/users/tempのディレクトリにあるファイルを全て消去するcrontabは、

30 18 * * * rm /home/users/tmp/*

毎日午前11時に行う場合は、

 0 11 * * rm /home/users/tmp/*

1月、6月の1日、00:30に行う場合、

30 0 1 1,6 * rm /home/users/tmp/*

毎月の1日、10日、15日の00:00に行う場合

0 0 1,10,15 * * rm /home/users/tmp/*

13日の金曜日、00:05と00:10に行う場合

5,10 0 13 * 5 rm /home/users/tmp/*

15分毎にあるスクリプトを実行する時には、

*/15 * * * * /path/to/script.sh

月曜から金曜日までの15分毎にスクリプトを実行する場合、

*/15 * * * 1-5 /path/to/script.sh

crontab enviroment

cronジョブは、ターミナルを経由して実行されるわけではないので、環境指定はcrontab内で行う必要がある。また、実行ディレクトリは、cronジョブを指定したユーザーのホームディレクトリとなる。
crontabの環境にzshを指定したい場合、実行スクリプトに書き込み、さらにanacondaで指定したpythonを仕様したい場合はcrontabで、condaを初期化(initiate)するために、source ~/.zshrcを行ってから、condaの環境をアクティベイトする。その後に、pythonファイルを実行すれば良い。

SHELL=/bin/zsh

* * * * * source $PWD/.zshrc; conda activate your_env >> /tmp/cronpy.log 2>&1; python3 /path/to/file/main.py  >> /tmp/cronpy.txt 2>&1

出力ファイルの/tmp/cronpy.logに続く$${2>&1}$$で、標準出力と標準エラー出力の両方をフィアルに書き込む。

scheduleモジュール

Jupyter notebook やPythonコード内で定期的実行を行うには、scheduleを使う。scheduleのインストールは以下の通り。

pip install schedule

定期実行の関数を指定する。

import time
import datetime
from schedule import every, repeat, run_pending, CancelJob

def job1():
    print("Hello",datetime.datetime.now())

def job2(name):
    print('Hi',name,datetime.datetime.now())

def job3():
    print("Good Morning",datetime.datetime.now())

schedule.every(1).seconds.do(job1)  # 関数job1を、1秒毎に実行する
schedule.every(2).minutes.do(job1)  # 関数job1を、2分毎に実行する
schedule.every(3).hours.do(job1)  # 関数job1を、2時間毎に実行する
schedule.every(4).days.do(job1)  # 関数job1を、4日毎に実行する
schedule.every(5).weeks.do(job1)  # 関数job1を、5週間毎に実行する
schedule.every(6).months.do(job1)  # 関数job1を、2時間毎に実行する

schedule.every().minute.at(":7").do(job3)  # 関数job3を、毎分7秒に実行する
schedule.every().hour.at(":8").do(job3)  # 関数job3を、毎時間8分に実行する
schedule.every(5).hours.at("9:10").do(job3)  # 関数job3を、5時間毎の9分10秒に実行する

schedule.every().day.at("11:12").do(job3)  # 関数job3を、毎日11時12分に実行する
schedule.every().monday.do(job3)  # 関数job3を、毎月曜日に実行する
schedule.every().tuesday.at("9:10").do(job3)  # 関数job3を、毎火曜日の9分10秒に実行する

schedule.every(2).seconds.do(jobs, name='Bob')# 関数job2を、引数Bobで2秒毎に実行する

定期的実行のジョブと繰り返し時間間隔を指定したのちに、ループで実行する。同日正午まで実行したい場合場合は、以下のように実行する。

year   = date.today().year
month  = date.today().month
hour   = 12
minute = 0
second = 0
set_until_time = datetime(year,month,date.today().day,hour,minute,second)

while datetime.now() < set_until_time:
    run_pending()
    time.sleep(1)




この記事が気に入ったらサポートをしてみませんか?