LoginSignup
22
16

More than 3 years have passed since last update.

venv環境でpythonスクリプトをcronで周期実行

Last updated at Posted at 2020-01-26

cronにpythonのジョブを登録してvenv環境で周期実行するためには

結論

使いたいvenv環境下のpythonを使えばよい。

$ crontab -e
* * * * * cd [絶対パス]; venv/bin/python foo.py

具体例

一分に一回、日時をjsonline形式でファイルに書き出したい。

OS環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G87

ディレクトリを作り、venv仮想環境作り、今回使うパッケージjsonlinesをインストール。

$ mkdir [場所]
$ cd [場所]
$ python -V
Python 3.7.1
$ python -m venv venv
$ source venv/bin/activate
(venv) $ pip install jsonlines

pythonスクリプトを書く。処理された日時をjsonlineとして、out.jsonlに書き出す、というものです。確認のためprintも。

dt2jsonl.py
import datetime
import jsonlines

dt = datetime.datetime.now()
dict_now = {'date': str(dt.date()), 'time': str(dt.time())}

with jsonlines.open('out.jsonl', mode='a') as writer:
    writer.write(dict_now)

print('updated: '+ str(dt))

処理させるとこんな感じでアウトプットが。

(venv) $ python dt2jsonl.py
updated: 2020-01-26 17:39:23.435616
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}

python dt2jsonl.py のままcronに登録してみる。 * * * * *なので一分に一回処理されるはず。
エラーとprint結果を確認するため、>> /tmp/cron.log 2>&1でstderrとstdoutを/tmp/cron.logに書き出すようにする。

(venv) $ crontab -e
* * * * * python dt2jsonl.py >> /tmp/cron.log 2>&1

待っていると/tmp/cron.logにエラーが

(venv) $ tail -f /tmp/cron.log
python: can't open file 'dt2jsonl.py': [Errno 2] No such file or directory

dt2jsonl.pyが見つからないらしいので、cronがどこにいるのか確認。

(venv) $ crontab -e
* * * * * pwd >> /tmp/cron.log 2>&1
(venv) $ tail -f /tmp/cron.log
/Users/[ユーザ]

ユーザディレクトリにいるので、スクリプトの絶対パスを教えてあげる。

(venv) $ crontab -e
* * * * * python /Users/[ユーザ]/[場所]/dt2jsonl.py >> /tmp/cron.log 2>&1
(venv) $ tail -f /tmp/cron.log
Traceback (most recent call last):
  File "/Users/[ユーザ]/[場所]/dt2jsonl.py", line 2, in <module>
    import jsonlines
ImportError: No module named jsonlines

今度はpythonスクリプトにたどり着いたが、jsonlinesがないと。venv環境で実行されてないので、cronはどのpythonを使っているのか確認。

(venv) $ crontab -e
* * * * * which python >> /tmp/cron.log 2>&1; python -V >> /tmp/cron.log 2>&1
(venv) $ tail -f /tmp/cron.log
/usr/bin/python
Python 2.7.10

システムのpython2.7を使っているので、なんとかするべき。
どのpythonを使うべきかチェック。

(venv) $ which python
/Users/[ユーザ]/[場所]/venv/bin/python

venv下のpythonに書き換える。

(venv) $ crontab -e
* * * * * /Users/[ユーザ]/[場所]/venv/bin/python /Users/[ユーザ]/[場所]/dt2jsonl.py >> /tmp/cron.log 2>&1

ちょっと待つと、/tmp/cron.logにprintの結果がでた。

(venv) $ tail -f /tmp/cron.log
updated: 2020-01-26 17:48:00.924120
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}

out.jsonlにもjsonlineとして書き出されていると思いきや、最初に手動で実行したもので、cronで実行された結果ではない。
ユーザディレクトリで実行されたので、ユーザディレクトリにあった。

(venv) $ cat ~/out.jsonl
{"date": "2020-01-26", "time": "17:48:00.924120"}
{"date": "2020-01-26", "time": "17:49:01.102146"}
{"date": "2020-01-26", "time": "17:50:00.278025"}

アウトプットの場所が違いますが、cronはvenv環境で処理してくれた。
pythonスクリプトのアウトプットを絶対パスで指定するのもいいですが、
今回はcronの実行ディレクトリを変える。

(venv) $ crontab -e
* * * * * cd /Users/[ユーザ]/[場所]; venv/bin/python dt2jsonl.py >> /tmp/cron.log 2>&1

これで期待通りになった。

(venv) $ tail -f /tmp/cron.log
updated: 2020-01-26 17:55:00.837256
(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}
{"date": "2020-01-26", "time": "17:55:00.837256"}

ちょっと待つと

(venv) $ cat out.jsonl
{"date": "2020-01-26", "time": "17:39:23.435616"}
{"date": "2020-01-26", "time": "17:55:00.837256"}
{"date": "2020-01-26", "time": "17:56:00.986909"}
{"date": "2020-01-26", "time": "17:57:01.167183"}
{"date": "2020-01-26", "time": "17:58:00.273073"}
22
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
16