Edited at

【Python】crontabで、ファイルを読み込むスクリプトを動かす時にpathlibを使うと楽だった

More than 1 year has passed since last update.


crontabで設定ファイルが読み込まれない

普段はpythonで仮想通貨の自動取引Botを作ったりしているのですが、息抜きに全く関係ない大学用のTwitterBotを作りました。

KU休講情報Bot

このBotは講義が終わるたびにその日の休講情報を呟くものです。

これをcrontabで定期実行させようと考えました。

しかし、設定をしても同じディレクトリにあるアクセストークン等が書かれたjsonファイルが読み込まれない。おかしいと思いログをあさってみると、No such file or directory

調べてみるとcrontabのカレントディレクトリがホームディレクトリにあることが原因でした。


解決法

先に解決法を書いておきます。以下のようにコードを変更しました。


  • 変更前

f = open("./hoge.json","r") #相対パスでは読み込まれずエラーが起きる


  • 変更後

from pathlib import Path

path = Path.cwd() / Path(__file__).parents[0] / "hoge.json"
f = open(path,"r")


原因


crontabのカレントディレクトリはホームディレクトリ

crontabのカレントディレクトリはホームディレクトリであり、スクリプトがあるディレクトリではありません。よって、./hoge.jsonのように書くとファイルが読み込まれません。


なぜpathlibを使うのか


異なる環境でも動作する

相対パスでエラーが起きてしまう場合、絶対パスでファイルを参照したりしますが、それだと別の環境下(WindowsとLinuxなど)で使えません。引数でファイルパスを設定するのもありですが、毎回するのは面倒くさいです。

そんな時にpathlibは効果を発揮します。pathlibはPython3.4で追加された公式のモジュールです。

pathlibはパスを表すクラスを提供し、パス通しの連結を/で行います。

from pathlib import Path

hoge = Path("hoge")
fuga = Path("fuga.py")
print(hoge / fuga)

# > hoge/fuga.py (Linux)
# > hoge\fuga.py(Windows)

パス通しの連結の際に自動的にOSに準拠した表記になり、異なる環境でも動作します。


上位パスにアクセスしやすい

pathlibは上位パスをparents[n]で取得できます。

from pathlib import Path

path = Path("aaa/bbb/ccc/ddd")
print(path)
print(path.parents[0])
print(path.parents[1])

# > aaa/bbb/ccc/ddd
# > aaa/bbb/ccc
# > aaa/bbb


open()の引数に使える

pythonでファイルを読み込む場合、大抵open()が使われますが、この引数にPath()を使うことができます。(Pytho3.6から)


後は目的のディレクトリまでパスをつなげるだけ

これらを用いれば先に書いたようにパスを指定できます。

path = Path.cwd() / Path(__file__).parents[0] / "hoge.json"

Path.cwd()はカレントディレクトリを返すクラスメソッドです。

また__file__はスクリプトの絶対パスを表します。よって、スクリプトと同じ階層にあるファイルを読み込む場合は、Path(__file__).parents[0]と一つ上の階層のパスを用います。


参考


  1. 11.1. pathlib — オブジェクト指向のファイルシステムパス

  2. Python3.4以降ならos.pathはさっさと捨ててpathlibを使うべき

  3. cronの設定方法