手元のパソコンで回すと、何が困るのか
Python で書いたスクリプトは、書いた時点では「動かしたいときに動かすもの」です。ところが、しばらく使っていると必ずこう思います。これ、勝手に動いていてほしい。
毎朝データを取ってくる。1時間おきに在庫を見る。届いた通知をためて集計する。どれも、人が席に座っている必要はありません。それでもパソコンで回していると、こうなります。
- パソコンを閉じると止まる。出先では動かない
- 更新で再起動がかかり、朝には止まっている
- 長い処理の途中で席を立てない
- つけっぱなしの電気代が、月に数百円から千円ほどかかる
置き場所を移すと、この全部がなくなります。そして月30円は、つけっぱなしの電気代より安いのが普通です。
どのくらいのスペックが要るのか
Python のスクリプトで効いてくるのは、ほとんどの場合メモリです。読み込むデータの大きさで決まります。
| やりたいこと | メモリの目安 | 向いている構成 |
|---|---|---|
| APIを叩いて結果を保存する | 〜128MB | ミニ(256MB) |
| ページを取得して中身を取り出す | 128〜300MB | ベーシック(512MB) |
| 数万行の表をまとめて処理する | 300MB〜1GB | プラス(1GB)/メモリ ベーシック |
| 大きな表を丸ごと読み込む | 1GB〜 | メモリ プラス(2GB)以上 |
pandas のように表を丸ごとメモリに載せるライブラリを使うと、一気に必要量が増えます。読み込むファイルのサイズの、3〜5倍を見ておくと外しません。
標準プランと大容量メモリプラン、どちらを選ぶか
同じくらいの値段で比べたとき、標準プランは CPU が多く、大容量メモリプランはメモリが多い構成です。
- 計算そのものが重い(変換、集計、繰り返しが多い)→ 標準プラン
- データを抱えたままにする(大きな表、キャッシュ)→ 大容量メモリプラン
決まった時刻に動かす(定期実行)
「毎朝7時に1回」「10分おきに1回」といった動かし方は、cron の書式で指定できます。書き方は5つの数字です。
# 分 時 日 月 曜日
0 7 * * * 毎日 7:00 に1回
*/10 * * * * 10分おき
0 */3 * * * 3時間おき
0 9 * * 1 毎週月曜の 9:00
スクリプト側で while True: と time.sleep() を使って待つ方法もありますが、決まった時刻に動かすなら定期実行のほうが確実です。処理が終わればプログラムは終了するので、メモリを抱えたままになりません。
逆に、常に起動していてほしいもの(受信を待ち続ける、常時監視する)は、定期実行ではなく常駐で動かしてください。落ちても自動で立ち上げ直します。
置いてから動かすまで
- 残高を入れる。クレジットカード・PayPay・銀行振込・Apple Pay・Google Pay が使えます。
- 構成と期間を選んで購入する。買った時点で使えるようになります。
- ファイルを置く。ブラウザからアップロードするか、その場で書けます。SSH は要りません。
- 依存を入れて起動する。
requirements.txtを置いておけば、必要なライブラリがまとめて入ります。
requirements.txt を必ず置く
手元で pip install したものは、置き場所には入っていません。次のように書き出して、一緒に置いてください。
pip freeze > requirements.txt
秘密の値はコードに書かない
APIキーやパスワードは、コードに直接書かず環境変数から読んでください。パネルから設定できます。
import os
API_KEY = os.environ["API_KEY"]
止まらないようにする
常駐させるプログラムは、いつか必ず落ちます。相手のサーバーが応答しなかった、想定外のデータが来た、通信が切れた。どれも普通に起きることです。
ASHIKA Network では異常終了を検知して自動で立ち上げ直しますので、落ちたまま朝を迎えることはありません。そのうえで、スクリプト側も次の2つだけ気をつけておくと安定します。
- 外と通信するところは必ず
tryで囲む。1回の失敗で全部が止まらないようにする - 途中経過をファイルかDBに書く。立ち上げ直したときに、続きから始められるようにする
import time
while True:
try:
do_work()
except Exception as e:
print("失敗しました:", e)
time.sleep(60)
ログの見かた
print() で出した内容は、ブラウザの画面にそのまま流れます。動いているかどうかを見るだけなら、これで足ります。
長く動かすものは、時刻を一緒に出しておくと後から追いやすくなります。
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)
logging.info("処理を始めます")
よくあるつまずき
ModuleNotFoundError が出る
ライブラリが入っていません。requirements.txt を置いて、入れ直してください。手元で入れたものは自動では付いてきません。
文字化けする
ファイルを開くときに、文字コードを指定してください。指定しないと、環境によって読み方が変わります。
open("data.csv", encoding="utf-8")
時刻が9時間ずれる
サーバーの時計は世界標準時で動いていることがあります。日本時間で扱いたいときは、タイムゾーンを明示してください。
from datetime import datetime, timezone, timedelta
JST = timezone(timedelta(hours=9))
print(datetime.now(JST))
途中で落ちる
メモリ不足を疑ってください。大きなファイルを一度に読まず、少しずつ処理するように変えるか、構成を1つ上げるかのどちらかです。
