レンタルサーバーの Cron を利用すると、定期的に Python コードを実行することができます。サーバーで動作するため、自分のパソコンが起動していない時でも実行できて便利です。スターサーバーさんでは、ライトプラン以上の契約で Cron を利用することができます。
Cron の一例として、Python の公式RSSに更新があった場合にメールで通知されるようにしてみたいと思います。
1. 実行するファイル(.py)のアップロード
まずは、実行するファイル(.py)をサーバーにアップロードします。サンプルコードは最後に載せてあります。
サーバー管理ツールにログインし、「FTPアカウント設定」から WebFTP にログインします。初期設定FTPアカウントが初めから1つ用意されていますので、これを利用しましょう。
ファイルマネージャーが開いたら、任意の場所にファイルをアップロードします。特に決まりはありませんが、他のファイルと混同しないよう、ルートディレクトリに Cron 専用のディレクトリを作成することをお勧めします。
ファイルマネージャーの使い方は特に難しくないと思います。詳しくは マニュアル > ファイルマネージャー をご参照ください。
2. パーミッション設定
Cron で実行するファイルは、オーナーが読み込みできれば充分です。グループやその他に読み込み権限を与える必要はありません。そのため、ファイルマネージャーの歯車アイコンから以下のようにパーミッションを変更します。
対象 | パーミッション設定 | 初期設定 |
---|---|---|
Cron 専用ディレクトリ | 700 | 705 |
Cron で実行するファイル | 600 | 604 |
これで、その他に与えられていた権限が取り除かれ、オーナーしか読み込みができなくなります。
3. Cron の設定
サーバー管理ツールに戻り、「Cron設定」から「通知先の設定」および「CRON追加」を行います。
「通知メールアドレス」には、実行結果の標準出力と標準エラーとが通知されます。そのどちらもない場合には、何も通知されません。実行するコードの中で必要な場合にのみ標準出力を行うことで、毎回メールが送られてくるのを避けることができます。
「CRON追加」タブでは、実行するタイミングやコマンドを指定することができます。
タイミングの設定は、数値もしくは「*」を入力するだけです。「*」は毎分、毎時間といった意味になります。便利な使い方として、カンマ区切りで複数のタイミングを指定することができます。上図では「時」に「6,18」と入力していて、こうすると毎日6時および18時に実行されます。
「コマンド」には、実行するコマンドを入力します。Windows のコマンドプロンプトで .py を実行するのと同じように、Python 本体に .py を渡す形式で記述します。
/user/bin/python3.6 /home/(サーバーID)/ekapyw.byte.jp/public_html/Cron専用ディレクトリ/実行ファイル.py
「/user/bin/python3.6」の部分が Python 本体です。これは マニュアル > WEBサーバーの仕様 を見ればコマンドパスとして載っています。
半角スペースを空けて .py ファイルのパスを記述します。先にアップロードしたファイルのパスを指定するだけですが、ファイルマネージャーで表示されたルートディレクトリに至るパス(/home ~ /public_html の部分)も書かなければいけないので、それを調べます。
「FTPアカウント設定」の「FTPアカウント一覧」を開きます。FTPアカウントの「編集」ボタンを押すと「FTPアカウント編集」画面になります。「パス」に記載されているのがルートディレクトリのパスです。ファイルマネージャーでは、一見ドメイン名がルートディレクトリかのように表示されますが、実際には「public_html」が入ります。
4. RSSを取得するサンプルコード
最後にサンプルコードを示します。Python の公式RSSに更新があった場合にのみ、その日時とタイトルを標準出力に書き出します。
#! /usr/bin/python3 -I -S
"""When Python release news is updated within 12 hours, the information is
printed to standard output.
"""
from calendar import month_abbr
from datetime import datetime, timedelta
from traceback import print_exc
from urllib.request import urlopen
from xml.etree import ElementTree
# ==============================
def main():
_now = datetime.now()
_published, _title = _python_release_news()
if (_now - _published) <= timedelta(hours=12):
print(f'[{_published}] {_title}')
# ==============================
def _python_release_news() -> tuple:
"""Returns the datetime and title of the latest Python release news."""
_url = 'https://blog.python.org/feeds/posts/default?alt=rss'
try:
with urlopen(_url) as _response:
_xml = ElementTree.parse(_response).getroot()
except:
print_exc()
else:
for i in _xml.iter('item'):
_pubdate = i.find('pubDate').text
_week, _day, _month, _year, _time, _zone = _pubdate.split()
_datetime = datetime(
int(_year),
list(month_abbr).index(_month),
int(_day),
*[int(t) for t in _time.split(':')],
)
return (_datetime, i.find('title').text)
return (datetime.min, '')
# ==============================
if __name__ == '__main__':
main()
これを Cron で実行すると、RSSに更新があった場合、もしくは何らかのエラーが起きた場合にのみメールが来るようになります。何もないときはメールが来ません。
信頼できるソースからのRSSは xml.etree.ElementTree で処理できます。_python_release_news() で、「pubDate」から日時を、「title」からタイトルを取得し、datetime オブジェクトとタイトル文字列を返しています。
19行目で現在日時と更新日時を比較し、その差が12時間以内のときに標準出力を行っています。ここは、Cron 設定の「時」で1日2回実行する設定をしていますので、その間隔と合わせるようにします。
このサンプルでは、RSSをイテレーションした最初の項目、つまり最新の投稿をそのまま出力しています。必要に応じて、タイトルの文字列でフィルタリングするなど、出力する項目を選別すると良いでしょう。