閉じる

Python×scheduleで定期実行入門|毎日・毎時・平日だけも一発設定

Pythonでの定期実行は、ちょっとした自動化やバッチ処理を作るうえで非常に便利です。

本記事では、軽量ライブラリ「schedule」を使って、毎日・毎時・平日だけ、などの定期実行をシンプルなコードで実現する方法を詳しく解説します。

cronよりわかりやすく、初心者でも扱いやすい方法を中心に紹介します。

Python×scheduleとは

scheduleライブラリの概要

scheduleは、Python用の軽量なジョブスケジューラーです。

バックグラウンドで常駐する巨大な仕組みではなく、1つのPythonスクリプトの中で「何を」「いつ」実行するかをシンプルに書けるライブラリです。

特徴として、次のような点があります。

  • cronのような難しい書式を覚える必要がない
  • Pythonのコードだけで完結する
  • 毎日・毎時・毎分・平日だけなどの指定が簡単
  • プロセスとして動いている間だけスケジュールが有効

どんな用途に向いているか

たとえば次のような用途で活躍します。

  • 毎日決まった時間にAPIからデータを取得しファイル保存する
  • 5分おきにWebサイトをチェックして異常を検知する
  • 平日9:00にSlackへリマインドメッセージを送る
  • 1時間ごとにログを集計してレポートを作る

「サーバを常時動かしておける」「Pythonスクリプトを動かしっぱなしにできる」環境であれば、scheduleはとても扱いやすい選択肢になります。

インストールと基本的な使い方

インストール方法

まずはpipでscheduleをインストールします。

Shell
pip install schedule

仮想環境を使っている場合は、仮想環境をアクティブにしてから実行してください。

最小構成のサンプル

「1分ごとにメッセージを表示する」最小構成のサンプルです。

Python
import schedule
import time

# 実行したい処理を関数として定義します
def job():
    # 実際の処理の代わりに、ここではメッセージを表示します
    print("1分ごとに実行されています")

# スケジュールの設定を行います
# every(1).minutes で「1分ごと」を意味します
schedule.every(1).minutes.do(job)

# 永久ループでスケジュールされたジョブを監視・実行します
while True:
    # 実行時刻になっているジョブがあれば実行します
    schedule.run_pending()
    # CPUを占有しないように1秒スリープします
    time.sleep(1)

上のコードを実行すると、1分ごとにメッセージが出力され続けます。

このサンプルからわかるように、scheduleの基本構成は「関数定義」「スケジュール設定」「無限ループ」の3要素です。

毎日・毎時・毎分の定期実行

毎日決まった時刻に実行する

「毎日◯時◯分」の実行は、最もよく使われるパターンの1つです。

たとえば毎日23:30にバックアップ処理を実行するコードは次のようになります。

Python
import schedule
import time
from datetime import datetime

def backup():
    # ここにバックアップ処理を書くイメージです
    print(f"バックアップ実行: {datetime.now()}")

# 毎日23:30にbackup関数を実行します
schedule.every().day.at("23:30").do(backup)

while True:
    schedule.run_pending()
    time.sleep(1)

ポイントはevery().day.at("HH:MM")という書き方です。

24時間表記で、”08:00″ や “19:45” のように指定できます。

毎時決まったタイミングで実行する

毎時ちょうど(例: 10:00, 11:00, 12:00, …)に処理したい場合は次のように書けます。

Python
import schedule
import time
from datetime import datetime

def hourly_job():
    print(f"毎時ちょうどの処理: {datetime.now()}")

# 毎時0分に実行するイメージ
schedule.every().hour.at(":00").do(hourly_job)

while True:
    schedule.run_pending()
    time.sleep(1)

every().hour.at(":00")のように、分だけを指定する書き方が可能です。

“:30” とすれば「毎時30分」に実行することもできます。

毎分・数分おき・数時間おきの実行

時間間隔ベースでの定期実行はさらに簡単です。

毎分実行、5分ごと、2時間ごとなどは次のように書きます。

Python
import schedule
import time
from datetime import datetime

def check_status():
    print(f"システム状態チェック: {datetime.now()}")

def report():
    print(f"簡易レポート出力: {datetime.now()}")

# 1分ごとに状態チェック
schedule.every(1).minutes.do(check_status)

# 5分ごとにレポート出力
schedule.every(5).minutes.do(report)

# 2時間ごとにレポート出力(例)
# schedule.every(2).hours.do(report)

while True:
    schedule.run_pending()
    time.sleep(1)

every(n).minutesevery(n).hoursのように、数字を変えるだけで簡単に間隔を調整できます。

平日だけ/特定曜日だけの定期実行

平日のみ実行する

業務でよくあるケースとして「平日のみ定期実行したい」というニーズがあります。

scheduleでは曜日指定がそのままメソッド名で用意されているため、直感的に記述できます。

Python
import schedule
import time
from datetime import datetime

def weekday_task():
    print(f"平日タスク実行: {datetime.now()}")

# 月曜から金曜の9:30に実行します
schedule.every().monday.at("09:30").do(weekday_task)
schedule.every().tuesday.at("09:30").do(weekday_task)
schedule.every().wednesday.at("09:30").do(weekday_task)
schedule.every().thursday.at("09:30").do(weekday_task)
schedule.every().friday.at("09:30").do(weekday_task)

while True:
    schedule.run_pending()
    time.sleep(1)

少し冗長に見えますが、「平日だけ」のような抽象的な指定はscheduleにはないため、曜日ごとに設定するのが基本です。

特定の曜日だけ実行する

特定の曜日だけでよければ、1行でシンプルに書けます。

Python
import schedule
import time
from datetime import datetime

def weekly_report():
    print(f"週次レポート作成: {datetime.now()}")

# 毎週月曜日の10:00に実行
schedule.every().monday.at("10:00").do(weekly_report)

while True:
    schedule.run_pending()
    time.sleep(1)

利用できる曜日メソッドは次の通りです。

曜日メソッド名の例
月曜every().monday
火曜every().tuesday
水曜every().wednesday
木曜every().thursday
金曜every().friday
土曜every().saturday
日曜every().sunday

複数ジョブの同時スケジュール

1つのスクリプトで複数タスクを管理する

scheduleは、1つのスクリプト内で複数のジョブをまとめて管理できます。

たとえば次のような構成が可能です。

Python
import schedule
import time
from datetime import datetime

def backup():
    print(f"[バックアップ] {datetime.now()}")

def health_check():
    print(f"[ヘルスチェック] {datetime.now()}")

def weekly_report():
    print(f"[週次レポート] {datetime.now()}")

# 毎日23:00にバックアップ
schedule.every().day.at("23:00").do(backup)

# 5分ごとにヘルスチェック
schedule.every(5).minutes.do(health_check)

# 毎週月曜10:00に週次レポート
schedule.every().monday.at("10:00").do(weekly_report)

while True:
    schedule.run_pending()
    time.sleep(1)

ループは1つだけでよく、すべてのジョブは共通のschedule.run_pending()によって管理されます。

ジョブに引数を渡す

実行する関数に引数を渡すことも可能です。

たとえば、メール送信先や処理モードを引数で切り替えるような場合です。

Python
import schedule
import time
from datetime import datetime

def send_report(report_type, to):
    print(f"[{report_type}] を {to} に送信: {datetime.now()}")

# 引数付きでジョブ登録
schedule.every().day.at("09:00").do(
    send_report,
    report_type="日次レポート",
    to="team@example.com",
)

schedule.every().monday.at("09:30").do(
    send_report,
    report_type="週次レポート",
    to="boss@example.com",
)

while True:
    schedule.run_pending()
    time.sleep(1)

キーワード引数もそのまま指定できるため、読みやすく保ったまま柔軟なジョブを組み立てられます。

scheduleを使う際の注意点と工夫

スクリプトを動かし続ける必要がある

scheduleは「OSレベルの常駐サービス」ではありません。

あくまで「実行中のPythonプロセス内」でスケジューリングされるため、次の点に注意が必要です。

  • Pythonスクリプトが終了すると、スケジュールも止まる
  • サーバ再起動後は、スクリプトを再度起動し直す必要がある

実運用では、以下のような方法でスクリプトを常駐させます。

  • LinuxならsystemdsupervisorでPythonスクリプトを常時起動
  • 開発中であれば、ターミナルで実行したままにする

「cronの代替」として完全に置き換えるというより、cronなどと組み合わせて「cronがPythonを起動する」「中でscheduleが細かいスケジュールを管理する」構成にするケースも多いです。

長時間かかる処理とブロッキング

1つのジョブが長時間ブロックすると、他のジョブの実行タイミングがずれます。

schedule自体はシングルスレッドで、run_pending()の中で順にジョブを呼び出します。

そのため、10分かかる処理があると、その10分間は他のジョブが実行されません。

対策としては次のようなパターンがあります。

  • ジョブ内でスレッドやプロセスを立てて非同期実行する
  • ジョブの処理時間を短く保ち、重い処理は別のワーカーに委譲する

たとえば簡易的にスレッドで非同期実行するコードは次のようになります。

Python
import schedule
import time
import threading
from datetime import datetime

def heavy_task():
    print(f"[heavy_task start] {datetime.now()}")
    time.sleep(10)  # 重い処理をシミュレート
    print(f"[heavy_task end] {datetime.now()}")

def run_in_thread(job_func):
    # ジョブを別スレッドで実行するラッパーです
    job_thread = threading.Thread(target=job_func)
    job_thread.start()

# heavy_task をスレッドで実行するようにスケジュール
schedule.every(1).minutes.do(run_in_thread, heavy_task)

while True:
    schedule.run_pending()
    time.sleep(1)

このようにすることで、スケジューラーのメインループは軽量なまま保ちつつ、重い処理は別スレッドに逃がすことができます。

タイムゾーンと時刻のずれ

scheduleは基本的に実行環境のローカルタイムを前提に動きます。

サーバのタイムゾーン設定や夏時間(DST)の影響を受けるため、次の点に注意してください。

  • サーバの時刻・タイムゾーン設定が適切か確認する
  • UTCベースで運用したい場合は、サーバ自体をUTCにしておく
  • タイムゾーンを厳密に扱いたい場合は、cronやAirflowなどの他ツールも検討

schedule単体ではタイムゾーン指定などの高度な制御はできない点は、設計時に意識しておきましょう。

まとめ

Pythonのscheduleライブラリを使うと、毎日・毎時・平日だけといった定期実行を、直感的なPythonコードだけで実現できます。

「関数で処理を定義し、every()day.at()でスケジュールを指定し、while True: run_pending()で回し続ける」だけのシンプルな構成です。

一方で、スクリプトを常時起動しておく必要があることや、長時間処理をどう扱うかといった注意点もあります。

小規模な自動化やバッチ処理であれば、まずscheduleで試し、その限界を感じてからcronや専用ジョブ管理ツールへの移行を検討するのが現実的な進め方です。

業務自動化

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!