
夜中に動かしているPython、自動で止まってた…ログもなくて原因が追えない…。
「毎朝のレポート」や「在庫監視」を、壊れず静かに回したい…!
業務で落ちない自動化を作る鍵は、(1) 再実行安全(Idempotent)、(2) 観測可能(ログ・通知・メトリクス)、(3) 静かに動く(低負荷・規約順守)の3点。この記事では、最小の設計原則からそのまま使えるテンプレ(cron / Windowsタスク / APScheduler / GitHub Actions)まで、コピペで導入できる形でまとめました。
この記事で身に付く力
- 壊れにくい自動化の設計力(再実行安全/排他/原子置換)
- すぐ調査できる観測性(JSONログ/相関ID/通知)
- 運用の地雷回避(レート制御/規約順守/タイムゾーン)
関連記事:
>>Python実務の型:例外処理と構造化ログでエラーに強いコードを書く
>>もう事故らせない:PythonでCSV/JSON/Excelを安全に読み書きする実務レシピ
>>Webスクレイピング:requests×BeautifulSoupの基本|“合法×丁寧×再現性”でデータ取得を設計する
>>API入門:OpenAPI/HTTPの基本と“壊れない”Pythonクライアント設計(コピペOK)
>>【保存版】SQLite×Pythonで作る“ローカルDWH”——ETL・集計・レポート自動化の最短手順
>>作業時間を半減する環境構築:VSCode/タスクランナー|“保存で整う・ワンキーで回る”仕組み化テンプレ
>>データ可視化レポート納品の型:Tableau/Matplotlib|“図3点+結論1行+運用”で伝わる・続く・刺さる
>>【コピペOK】pytestで“壊れないPython”を作る12ステップ
よくあるトラブルは「3種類」
現場で崩れる原因はだいたい似ています。まずは敵を知りましょう。
- 二重実行で破壊:同時起動でファイル破損や重複送信。
- 沈黙クラッシュ:深夜に停止、翌朝の定例が空振り。誰も気づけない。
- 規約違反/高負荷:スクレイピングやAPIを高頻度で叩いて429/403。信頼を落とす。
解決は設計です。これから「再実行安全×観測可能×静かに動く」に分解し、テンプレを配布します。
現場で長く回る仕組みの共通点
筆者(ふみと)はデータ/マーケ職で10年、社内運用や副業を含め100件以上の自動化を設計してきました。落ちにくい仕組みには共通点があります。
- 入力→処理→出力の境界が明確(入力は読み取り専用、出力は原子置換)。
- 原子置換/ロック/リトライが標準。安全装置は最初から。
- JSONログ+相関IDで1秒調査。人に優しいログ。
- スケジューラは用途最小(cron/Task Scheduler/APScheduler)から。
設計原則(最小セット)
- 再実行安全(Idempotent):同じ日付/同じ入力で同じ成果物。
入力は読み取り専用、出力は一時ファイル→原子置換、同名成果物は完全生成→置換。 - 排他制御:ロックファイルで二重起動を防止。
- 観測可能性:JSON構造化ログ、相関ID、件数・所要時間を記録。
- リトライ/バックオフ:429/5xxのみ対象、上限つき。429は停止の判断も。
- 設定の外だし:
.env
/config.yml
。秘密は環境変数でGitに載せない。 - ドライラン:
--dry-run
で外部副作用を抑えて検証。
スケジューラの選び方(早見表)
目的 | 最小構成 | 強み | 弱み |
---|---|---|---|
単独PC/サーバで日次 | cron(Linux/macOS) / Windowsタスク | OS標準・軽い | UI/ログが素朴 |
Python内で時間管理 | APScheduler | 曜日/間隔/タイムゾーン管理が簡単 | プロセス終了で止まる |
リポジトリ単体の定期処理 | GitHub Actions(cron) | 無料枠・履歴/通知あり | 外部私有NW不可 |
本格ワークフロー/依存管理 | Airflow等 | DAG/再実行/可視化 | 学習コスト/重い |
原則は最小から。まずは cron / Task Scheduler、アプリ内だけなら APScheduler で十分です。
プロジェクト雛形(入出力/ログ/ロック)
auto_job/
app/
__init__.py
main.py # 入口(引数パース/ワイヤリング)
job.py # 業務ロジック本体(純粋関数を中心に)
io_utils.py # 原子置換/パス/ロック
logconf.py # JSONロガー+相関ID(任意)
config/
config.yml # 入出力パス/実行時設定
data/
in/ # 入力(読み取り専用)
work/ # 中間(Parquet/キャッシュ)
out/ # 出力(原子置換で置き換え)
tests/
test_job.py
io_utils.py(原子置換+ロック)
from pathlib import Path
import tempfile, os, time
class FileLock:
def **init**(self, path: Path, timeout: float = 0):
self.path, self.timeout = path, timeout
self.\_fd = None
def **enter**(self):
start = time.time()
while True:
try:
self.\_fd = os.open(self.path, os.O\_CREAT | os.O\_EXCL | os.O\_RDWR)
os.write(self.\_fd, str(os.getpid()).encode())
return self
except FileExistsError:
if time.time() - start > self.timeout:
raise TimeoutError(f"lock busy: {self.path}")
time.sleep(0.5)
def **exit**(self, \*exc):
try:
os.close(self.\_fd)
os.remove(self.path)
except Exception:
pass
def atomic\_write\_text(path: Path, text: str, encoding: str = "utf-8") -> None:
path.parent.mkdir(parents=True, exist\_ok=True)
with tempfile.NamedTemporaryFile("w", delete=False, dir=path.parent, encoding=encoding, newline="") as tmp:
tmp.write(text)
tmp\_path = Path(tmp.name)
os.replace(tmp\_path, path)
テンプレ:日次レポート(CSV→整形→Excel/メール)
まずは「手堅く価値が出る」日次レポート。pandas
→ExcelWriter
で吐き出します。
from pathlib import Path
import pandas as pd
def make\_report(src: Path, out\_xlsx: Path) -> dict:
df = pd.read\_csv(src, parse\_dates=\["date"], dtype={"store":"string"})
g = df.groupby(\[df\["date"].dt.date, "store"]).agg(sales=("sales","sum"))
g = g.reset\_index().rename(columns={"date":"day"})
with pd.ExcelWriter(out\_xlsx, engine="xlsxwriter") as w:
g.to\_excel(w, sheet\_name="日次売上", index=False)
return {"rows": int(len(df)), "groups": int(len(g))}
import argparse, json
from pathlib import Path
from datetime import datetime
from app.io_utils import FileLock
from app.job import make_report
DEF\_IN = Path("data/in/sales.csv")
DEF\_OUT = Path("data/out/report.xlsx")
parser = argparse.ArgumentParser()
parser.add\_argument("--src", type=Path, default=DEF\_IN)
parser.add\_argument("--out", type=Path, default=DEF\_OUT)
parser.add\_argument("--dry-run", action="store\_true")
if **name** == "**main**":
args = parser.parse\_args()
with FileLock(Path("data/.report.lock"), timeout=3):
stats = make\_report(args.src, args.out)
print(json.dumps({
"ts": datetime.now().isoformat(timespec="seconds"),
"rows": stats\["rows"], "groups": stats\["groups"],
"out": str(args.out)
}, ensure\_ascii=False))
スケジューリング(OS標準)
ログは日付付きで残すと調査が速いです。
# 毎朝 6:10 に実行、ログは日付付きで保存
10 6 * * * cd /path/to/auto_job && /usr/bin/python -m app.main \
>> logs/$(date +\%Y\%m\%d).log 2>&1
schtasks /Create /SC DAILY /ST 06:10 /TN AutoReport ^
/TR "cmd /c cd C:\path\auto_job && py -3 -m app.main >> logs\%date:~0,10%.log 2>&1"
テンプレ:APScheduler(Python内で柔軟スケジュール)
アプリ内で完結したいときに便利。常駐化は systemd などで。
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
from datetime import datetime
from pathlib import Path
from app.job import make_report
sched = BlockingScheduler(timezone="Asia/Tokyo")
@sched.scheduled\_job(CronTrigger(hour=6, minute=10))
def daily():
src = Path("data/in/sales.csv")
out = Path("data/out/report.xlsx")
info = make\_report(src, out)
print({"ts": datetime.now().isoformat(), \*\*info})
if **name** == "**main**":
sched.start()
サービス化:Linuxは systemd
、Windowsはサービス/タスクで常時起動に。
テンプレ:GitHub Actionsで“リポジトリ内ジョブ”
name: nightly
on:
schedule:
- cron: "10 21 * * *" # JST 6:10(UTC-9時間)
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
- run: pip install -r requirements.txt
- run: python -m app.main --src data/in/sales.csv --out data/out/report.xlsx
- uses: actions/upload-artifact@v4
with: { name: report, path: data/out/report.xlsx }
注意:私有NWや社内共有への直接書き込みは不可。成果物はArtifactで取得します。
テンプレ:価格監視(API/HTML)+通知(メール/Slack)
通知はダミー実装です。実運用では環境変数にキー/トークンを注入してください。
import smtplib, os
from email.message import EmailMessage
import json, urllib.request
def send\_mail(subject: str, body: str) -> None:
host = os.environ.get("SMTP\_HOST")
to = os.environ.get("MAIL\_TO")
if not host or not to:
return
msg = EmailMessage()
msg\["Subject"], msg\["From"], msg\["To"] = subject, to, to
msg.set\_content(body)
with smtplib.SMTP(host) as s:
s.send\_message(msg)
def send\_slack(text: str) -> None:
url = os.environ.get("SLACK\_WEBHOOK")
if not url:
return
data = json.dumps({"text": text}).encode()
req = urllib.request.Request(url, data=data, headers={"Content-Type":"application/json"})
urllib.request.urlopen(req, timeout=5)
運用の落とし穴と対策(早見表)
症状 | 原因 | 対策 |
---|---|---|
二重実行で壊れる | 同時起動/遅延 | ロックファイル、idempotent設計、原子置換 |
朝だけ遅い/失敗 | バックアップ/他バッチ衝突 | スケジュール分散、ジッタを加える |
429/403が出る | 高頻度/規約違反 | レート制御、robots/Terms確認、API優先 |
失敗に気づけない | ログ未整備 | JSONログ+通知でERROR以上を送る |
日付ズレる | タイムゾーン未考慮 | Asia/Tokyoで処理、保存はUTC/ISO8601 |
手元で動くのに本番で壊れる | パス/権限/依存 | Pathlib、相対→絶対、pip-tools/requirements |
ユースケース別「最初の一手」
- 社内CSV→Excelレポート:上記テンプレ(pandas→ExcelWriter)+ cron/Task。
- 価格/在庫監視:通知テンプレ+[内部リンク:Webスクレイピング]/[内部リンク:API入門]。429/規約に注意。
- DB/バックアップ:日次で SQLite/CSV/Parquet を日付付きで保存。[内部リンク:SQLite×Python]
- メール定例:通知に件数/差分を載せるだけで価値が上がる。
今日やること(45〜60分)
- 自動化したいタスクを入力→処理→出力に分解、idempotentに設計。
- 雛形を作成し、原子置換/ロックを入れる。
- cronまたはWindowsタスクで毎日1回回す。
- JSONログと通知(ダミー可)を繋いで、失敗に即気づける形に。
まとめ:小さく始め、静かに強く回す
自動化は大掛かりにしないのがコツ。まずは最小の設計(再実行安全/観測可能/静かに動く)を入れ、OS標準のスケジューラで確実に回す。積み上げた仕組みは、翌月のあなたの時間を救います。
筆者メモ(ふみと)
昔、在庫監視のスクリプトが深夜に沈黙し、翌朝の全社MTGで冷や汗…という事件が。原因は二重起動とログ不備でした。そこで原子置換とロック、JSONログ+通知を入れてからは、夜中に失敗してもすぐ復旧できるようになり、以降「朝の静けさ」を取り戻せました。この記事のテンプレは、その時の反省と改善を凝縮しています。
-
-
Python実務の型:例外処理と構造化ログでエラーに強いコードを書く
例外処理って、結局どこまでやれば“実務で困らない”の? ログも整えるのって大変そう…最低限の型、ください! この記事は、pythonbunseki.comの実務トーンで「防ぐ→気づく→復旧する」をコー ...
-
-
API入門:OpenAPI/HTTPの基本と“壊れない”Pythonクライアント設計(コピペOK)
API連携を始めたいけど、何から学べば“壊れない仕組み”になる? OpenAPI?HTTP?タイムアウト?……用語が多すぎて迷子になりがち。 本記事は、HTTPの基礎×OpenAPIの読み方×堅牢なク ...
-
-
Webスクレイピングの法的リスクと安全運用|“規約→同意→頻度→記録”でトラブルを回避する実務ガイド
「副業や社内でスクレイピングを使いたい。でも、どこまでOKで、何をするとNG?」 結論、“安全運用の型”を最初に決めると迷いません。鍵は規約 → 同意 → 頻度 → 記録。 重要:本記事は一般情報です ...
-
-
もう事故らせない:PythonでCSV/JSON/Excelを安全に読み書きする実務レシピ
CSV/JSON/Excelの読み書き、どこから気をつければいい? 文字化け・先頭ゼロ欠落・壊れたExcel……もう事故らせたくない! 結論:データ仕事の9割はI/O(入出力)。ここを整えるだけで、桁 ...
-
-
データ可視化レポート納品の型:Tableau/Matplotlib|“図3点+結論1行+運用”で伝わる・続く・刺さる
結論:レポートは「データ→図」ではなく「意思決定→図」の順で設計します。最短で伝わり、運用で続く“型”は、(1) 結論1行、(2) 図3点(推移・分解・構成)、(3) 打ち手(閾値/費用対効果)、(4 ...
伴走サポート:あなたの“定例仕事”を静かに動く仕組みに
無料カウンセリング/体験で、タスクの分解→設計→スケジュールまで同伴。落ちない運用を最短で作ります。
TechAcademy データサイエンスコース(受講料:174,600円~ ※更に割引あり)

株式会社キカガク AI人材長期育成コース(受講料:237,600円~)

最近のコメント