تشغيل سكربت بايثون تلقائيًا كل يوم أو ساعة | بايثون بالمثال 29

تشغيل سكربت بايثون تلقائيًا كل يوم أو ساعة باستخدام مكتبة schedule

هل تريد تشغيل سكربت بايثون تلقائيًا كل يوم أو ساعة، بدل فتح البرنامج وتشغيل الكود يدويًا في كل مرة؟ في هذا الدرس سنكتب أكوادًا جاهزة لتنفيذ مهمة كل عشر ثوانٍ، ثم كل ساعة أو يوم في وقت محدد باستخدام مكتبة schedule.

في الدرس 29 من سلسلة «بايثون بالمثال» لن نتوقف عند الجدولة داخل نافذة الطرفية؛ سنوضح أيضًا كيف تجعل Windows Task Scheduler أو cron في Linux يطلقان سكربتًا مستقلًا، وسنرفق مشروعًا عمليًا يحتفظ بسجل وقت كل تشغيل لتتحقق من النتائج بنفسك.

{alertInfo}المتطلبات: Python 3.9 أو أحدث، وتثبيت schedule للأمثلة الدورية داخل بايثون فقط. برنامج تسجيل التنفيذ المستقل يستخدم مكتبات Python المدمجة ويمكن تشغيله دون تثبيت schedule.

تحميل مشروع جدولة سكربتات بايثون

حمّل أكواد الدرس الخمسة، وملفات إعداد Windows وLinux، والاختبارات؛ وجرّب تشغيل المهام تلقائيًا على جهازك.

تحميل ملفات الدرس ZIP

{getToc} $title={محتوى المقال}


لماذا تحتاج إلى تشغيل سكربت بايثون تلقائيًا؟

قد تكتب سكربتًا يحدّث تقريرًا يوميًا، أو يسجل حالة مهمة كل ساعة، أو ينفّذ فحصًا دوريًا. بدل فتح الملف والضغط على «تشغيل» في كل مرة، يمكنك جدولة تشغيل سكربت بايثون تلقائيًا بحيث تنفذ المهمة في الموعد المطلوب.

سنستخدم مثالًا بسيطًا قابلًا للتحقق: يسجّل برنامج وقت تشغيله في ملف execution.log. لاحقًا سنشغّله كل عشر ثوانٍ داخل بايثون، ثم نجعله يُستدعى مرة يوميًا بواسطة نظام التشغيل. هذا يوضح الفرق بين الطريقتين دون الحاجة إلى حسابات خارجية أو اتصال بالإنترنت.

ما الفرق بين schedule وTask Scheduler وcron؟

الأداةمتى تختارها؟هل يجب أن تبقى عملية بايثون مفتوحة؟
scheduleتنفيذ دالة مرارًا أثناء تشغيل برنامج بايثون نفسهنعم؛ إنها جدولة داخل العملية الحالية
Task Schedulerبدء سكربت مستقل يوميًا أو في ساعة معينة على Windowsلا؛ نظام التشغيل يطلق العملية في الموعد
cronبدء سكربت مستقل وفق جدول على Linuxلا؛ خدمة cron تطلق العملية في الموعد
{alertWarning}الفارق الحاسم: إغلاق عملية Python يوقف وظائف schedule. أما Windows Task Scheduler وcron فيمكنهما بدء تشغيل جديد للسكربت دون فتحه يدويًا. ومع ذلك يجب أن يكون الجهاز قيد التشغيل ومستوفيًا لشروط الجدولة؛ فلا توجد طريقة محلية لتشغيل مهمة على جهاز مطفأ تمامًا.

الفرق بين مكتبة schedule وTask Scheduler وcron لجدولة تشغيل سكربتات بايثون

تثبيت مكتبة schedule وتجهيز المشروع

تحتاج إلى Python 3.9 أو أحدث في هذا الدرس. افتح الطرفية وتأكد من المفسّر المستخدم، ثم ثبّت المكتبة في البيئة نفسها:

python --version
python -m pip install schedule
python -m pip show schedule

مكتبة schedule صغيرة ومخصصة للجدولة داخل العملية، ويمكن الاطلاع على توثيقها الرسمي. أما ملف المهمة المستقلة الذي سنستخدمه مع نظام التشغيل فلا يحتاج إلى تثبيت أي مكتبة خارجية.

{alertWarning}تجنب تسمية ملفك schedule.py. ذلك قد يؤدي إلى استيراد ملفك بدل المكتبة، فتظهر أخطاء مثل AttributeError: module 'schedule' has no attribute 'every' عند تشغيل المثال.

أبسط كود: تشغيل دالة كل 10 ثوانٍ في بايثون

أنشئ ملفًا باسم first_schedule.py واكتب الكود التالي. اطبع وقت التنفيذ حتى ترى عمل الجدولة أمامك:

"""أول مثال: تشغيل وظيفة كل عشر ثوانٍ أثناء بقاء البرنامج مفتوحًا."""

import time
from datetime import datetime

import schedule


def job():
    print("تنفيذ المهمة:", datetime.now().strftime("%H:%M:%S"), flush=True)


schedule.every(10).seconds.do(job)
print("بدأت الجدولة؛ اضغط Ctrl+C للإيقاف.")
try:
    while True:
        schedule.run_pending()
        time.sleep(1)
except KeyboardInterrupt:
    print("تم إيقاف الجدولة.")

شغّل الملف باستخدام الأمر التالي:

python first_schedule.py

بعد نحو عشر ثوانٍ ستظهر الرسالة الأولى، ثم تتكرر. مثال توضيحي على شكل المخرجات، وقد تختلف الأوقات الفعلية:

بدأت الجدولة؛ اضغط Ctrl+C للإيقاف.
تنفيذ المهمة: 09:30:10
تنفيذ المهمة: 09:30:20
تنفيذ المهمة: 09:30:30
{alertSuccess}لن تنفّذ المهمة فور تشغيل الملف. عندما تكتب every(10).seconds فالتشغيل الأول يكون بعد الفترة المحددة تقريبًا. لإجراء تجربة فورية يمكنك استدعاء الدالة job() مباشرة قبل دخول الحلقة.

شرح every وdo وrun_pending وsleep

جزء الكودمهمته
schedule.every(10).secondsإنشاء جدول بفاصل 10 ثوانٍ
.do(job)ربط الوظيفة المراد تنفيذها بالجدول
schedule.run_pending()تشغيل الوظائف التي حان موعدها في هذه اللحظة
time.sleep(1)تقليل استهلاك المعالج بين عمليات التحقق
Ctrl+Cإيقاف الحلقة وإغلاق البرنامج

الدالة run_pending() لا تعوّض جميع مرات التشغيل الفائتة. إذا كان البرنامج متوقفًا ساعة كاملة، فلا تتوقع تنفيذ المهمة كل دقيقة عن الماضي عند إعادة فتحه. كما أن الوظائف الطويلة قد تؤخر وظائف أخرى لأنها تُنفذ تسلسليًا في المثال البسيط.

شرح عمل schedule.run_pending في بايثون لفحص المهام المجدولة وتنفيذها في الوقت المحدد

تشغيل سكربت بايثون كل ساعة أو يوميًا في وقت محدد

الجدولة كل ساعة تستخدم every().hour، والجدولة اليومية عند التاسعة صباحًا تستخدم every().day.at("09:00"). المثال التالي يستعمل schedule.Scheduler() مستقلاً حتى تصبح إدارة مجموعة الوظائف أسهل:

"""مثال جدولة وظيفة كل ساعة ووظيفة يوميًا عند 09:00."""

import time
from datetime import datetime

import schedule


def show_message(label):
    print(f"{datetime.now():%Y-%m-%d %H:%M:%S} | {label}", flush=True)


scheduler = schedule.Scheduler()
scheduler.every().hour.do(show_message, "المهمة التي تعمل كل ساعة")
scheduler.every().day.at("09:00").do(show_message, "المهمة اليومية")
for job in scheduler.jobs:
    print("موعد التنفيذ القادم:", job.next_run)

try:
    while True:
        scheduler.run_pending()
        time.sleep(1)
except KeyboardInterrupt:
    print("تم إيقاف الجدولة.")

سيطبع البرنامج مواعيد التنفيذ القادمة الخاصة بكل وظيفة. وقد يختلف موعد التنفيذ اليومي بحسب توقيت الجهاز المحلي. إذا كانت الساعة التاسعة قد مرت اليوم، فسيكون الموعد التالي عادة في التاسعة من اليوم القادم ما دام البرنامج يعمل.

python daily_hourly.py
{alertInfo}هل تحتاج تشغيلًا عند التاسعة دون إبقاء Python مفتوحًا؟ انتقل إلى قسم Windows Task Scheduler أو cron. استخدام .day.at() وحده لا يجعل السكربت يعمل بعد إغلاقه.

تشغيل أكثر من مهمة وإلغاء جدول محدد

يمكنك تسجيل أكثر من وظيفة داخل Scheduler واحد، ووضع وسم لكل مجموعة حتى تُلغيها لاحقًا من خلال clear(). المثال التالي يطبع رسالتين بفاصلين مختلفين:

"""تجربة مهام متعددة مع إلغاء مهمة بالوسم."""

import time
import schedule


def work(label):
    print("تم تنفيذ:", label, flush=True)


scheduler = schedule.Scheduler()
scheduler.every(5).seconds.do(work, "الأولى").tag("fast")
scheduler.every(10).seconds.do(work, "الثانية").tag("slow")
print("عدد المهام:", len(scheduler.jobs))
print("لإيقاف مجموعة المهام السريعة استخدم: scheduler.clear('fast')")
try:
    while True:
        scheduler.run_pending()
        time.sleep(1)
except KeyboardInterrupt:
    print("تم إيقاف التشغيل.")

عندما تحتاج لإلغاء المجموعة السريعة داخل برنامجك، نفّذ scheduler.clear("fast")؛ ستتوقف الوظائف التي تحمل هذا الوسم فقط. ويمكن أيضًا حفظ الوظيفة الناتجة من do() ثم إلغاؤها باستخدام scheduler.cancel_job(job).

مشروع عملي: سكربت مستقل يسجل وقت تشغيل المهمة

هذه الخطوة أهم من طباعة رسالة عابرة: سنكتب ملفًا باسم task_once.py ينفّذ مهمة مرة واحدة عند استدعائه، ويسجل الوقت في output/execution.log. ستستخدم أنظمة الجدولة هذا السكربت مباشرة، ولذلك لا يحتوي على حلقة while True.

"""مهمة مستقلة قابلة للاستدعاء يدويًا أو من Task Scheduler أو cron.

تكتب وقت التنفيذ في output/execution.log بجوار ملفات المشروع.
لا تحتاج إلى مكتبة schedule.
"""

import argparse
from datetime import datetime
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent
DEFAULT_LOG = BASE_DIR / "output" / "execution.log"


def write_log(message="تشغيل تلقائي", log_path=None):
    """اكتب سطرًا في سجل UTF-8 وأرجع المسار الناتج."""
    if not isinstance(message, str) or not message.strip():
        raise ValueError("نص المهمة يجب ألا يكون فارغًا")
    path = Path(log_path) if log_path is not None else DEFAULT_LOG
    path.parent.mkdir(parents=True, exist_ok=True)
    clean_message = " ".join(message.splitlines()).strip()
    timestamp = datetime.now().astimezone().isoformat(timespec="seconds")
    with path.open("a", encoding="utf-8") as handle:
        handle.write(f"{timestamp} | {clean_message}\n")
    return path


def main(argv=None):
    parser = argparse.ArgumentParser(description="حفظ وقت تنفيذ مهمة مجدولة")
    parser.add_argument("--message", default="تشغيل تلقائي", help="نص يسجل مع وقت التنفيذ")
    args = parser.parse_args(argv)
    try:
        path = write_log(args.message)
    except (OSError, ValueError) as exc:
        parser.exit(1, f"خطأ: {exc}\n")
    print(f"تم التنفيذ وحفظ السجل: {path}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

جرّبه الآن دون جدولة:

python task_once.py --message "أول تشغيل"

سيُنشأ مجلد output بجوار السكربت تلقائيًا، وستجد سطرًا مشابهًا للآتي داخل execution.log:

2026-10-19T09:16:00+03:00 | أول تشغيل

هذا الناتج مثال توضيحي لشكل السجل وليس وقتًا ثابتًا في البرنامج؛ يكتب السكربت وقت جهازك الفعلي مع فرق التوقيت. استخدمنا Path(__file__).resolve().parent لتبقى ملفات السجل في مجلد المشروع حتى لو استُدعي السكربت من مجلد عمل آخر.

تجربة المشروع مع schedule وأمر تشغيل واحد

داخل حزمة الدرس ستجد أيضًا schedule_demo.py. يوفر خيارات سطر أوامر تجعل الاختبار أسهل، ويتصل بدالة تسجيل المهمة نفسها في task_once.py.

لإجراء ثلاثة تشغيلات تبدأ إحداها فورًا، ثم تتكرر كل عشر ثوانٍ، نفّذ:

python schedule_demo.py --every 10 --run-now --max-runs 3

ولتشغيل البرنامج كل يوم في التاسعة صباحًا ما دامت العملية مستمرة:

python schedule_demo.py --daily 09:00

يمكنك اختبار البرنامج على فترات أقصر باستخدام --every 1، أو إيقافه عبر Ctrl+C. ملف README.md المرفق يشرح كل المعاملات، ويحتوي المشروع على اختبارات وظائف التسجيل وإعداد خيارات الجدولة.

تشغيل سكربت بايثون يوميًا باستخدام Windows Task Scheduler

إذا أردت تشغيل السكربت عند ساعة محددة حتى بعد إغلاق نافذة CMD، فمن الأفضل أن ينشئ Windows عملية Python جديدة في الموعد، بدل إبقاء حلقة schedule في الطرفية.

  1. افتح Task Scheduler من قائمة ابدأ، ثم اختر Create Basic Task.
  2. اختر Daily وحدد وقتًا تجريبيًا مناسبًا، مثل 09:00.
  3. اختر Start a program ثم أدخل مسار المفسّر وملف المهمة كما هو موضح في الجدول.
  4. احفظ المهمة، ثم استخدم Run لاختبار تنفيذها فورًا.
  5. راجع ملف output/execution.log الموجود في مجلد المشروع للتحقق من تسجيل وقت التنفيذ.
الحقل داخل Task Schedulerمثال يجب تعديله وفق جهازك
Program/scriptC:\Python312\python.exe
Add arguments (optional)"C:\PythonProjects\python-schedule-example-29\task_once.py" --message "Windows daily"
Start in (optional)C:\PythonProjects\python-schedule-example-29

هذه مسارات افتراضية للتوضيح فقط. اعرف المسار الحقيقي لمفسّر Python على جهازك باستخدام:

python -c "import sys; print(sys.executable)"

إذا كانت لديك بيئة افتراضية، استخدم ملف python.exe الخاص بها. اكتب المسار الصحيح إلى task_once.py بين علامتي اقتباس في الوسائط، واكتب Start in على شكل مسار مجلد دون علامات اقتباس. قد يتأثر التشغيل بصلاحيات الحساب، أو شروط الطاقة، أو تعطيل المهام التي تأخرت؛ راجع إعدادات المهمة وحقل Last Run Result عند تشخيص المشكلة.

يمكنك الرجوع إلى مراجع Microsoft Task Scheduler وإلى توثيق schtasks الرسمي لفهم الخيارات المتاحة على إصدارات Windows المختلفة.

إعداد Windows Task Scheduler لتشغيل سكربت بايثون يوميًا باستخدام python.exe وتحديد ملف السكربت

تشغيل سكربت بايثون يوميًا في Linux باستخدام cron

في نظام Linux يمكن لخدمة cron إطلاق برنامج Python مستقل في أوقات محددة. اعرف مسار المفسّر أولًا، ثم افتح جدول المستخدم الحالي:

command -v python3
crontab -e

على سبيل المثال، يشغّل السطر التالي الملف يوميًا في الساعة 09:00 بحسب توقيت النظام المستخدم للجدولة. غيّر اسم المستخدم ومسارات الملفات قبل الحفظ:

0 9 * * * /usr/bin/python3 /home/USERNAME/python-schedule-example-29/task_once.py --message "Linux daily" >> /home/USERNAME/python-schedule-example-29/cron-output.log 2>&1

الرقم 0 يعني الدقيقة صفر، والرقم 9 يعني الساعة التاسعة. أما النجوم الثلاث الباقية فتعني كل يوم من الشهر، وكل شهر، وكل يوم من الأسبوع. سيُسجل task_once.py وقت التنفيذ داخل output/execution.log؛ ويحتفظ ملف cron-output.log برسائل التشغيل والأخطاء.

{alertWarning}مهم: استخدم المسار الصحيح للمفسّر، وخاصةً عند الاعتماد على بيئة افتراضية. ويجب أن يكون مجلد المشروع موجودًا قبل أول تشغيل حتى ينجح توجيه المخرجات إلى cron-output.log. كذلك لا تُشغّل ملف schedule_demo.py كل دقيقة بواسطة cron، لأن ذلك قد ينشئ عمليات مستمرة متعددة؛ استخدم task_once.py بدلاً منه.

هل تعمل المهمة إذا أغلقت CMD أو أطفأت الكمبيوتر؟

الحالةالنتيجة العامة
أغلقت عملية Python التي تحتوي scheduleتتوقف الجدولة داخل تلك العملية
أغلقت نافذة CMD ثم انتظرت موعد مهمة Windowsيمكن للجدولة تشغيل سكربت جديد إذا كانت المهمة مضبوطة والشروط مستوفاة
أغلقت الطرفية ثم انتظرت مهمة cronيمكن لـ cron إطلاق المهمة الجديدة إذا كانت خدمته تعمل
أطفأت الجهاز في وقت التنفيذلن ينفذ الجهاز المحلي برنامجًا وهو مطفأ؛ تختلف سياسة التعويض عند عودته حسب الأداة والإعدادات
أردت تنفيذًا مستمرًا طوال اليومتحتاج جهازًا أو خادمًا يظل متاحًا أو خدمة تشغيل مصممة لذلك

أيضًا schedule ليست أداة ذات دقة زمنية صارمة أو ضمان تنفيذ كل موعد فائت. إذا كانت مهمتك تتعلق بمواعيد حرجة أو أحمال كبيرة، فاختر نظامًا أكثر ملاءمة للجدولة والمراقبة.

أخطاء شائعة عند جدولة وتشغيل سكربت بايثون

الخطأ أو العرضالسبب الأقرب وما الذي تجربه؟
ModuleNotFoundError: No module named 'schedule'ثبّت المكتبة في المفسّر نفسه عبر python -m pip install schedule وتحقق من البيئة الافتراضية.
AttributeError: module 'schedule' has no attribute 'every'تأكد أن اسم ملفك ليس schedule.py، ولا يوجد ملف آخر بهذا الاسم يحجب المكتبة.
المهمة لا تبدأ فورًاتحدد every(10).seconds أول تشغيل بعد نحو عشر ثوانٍ؛ جرب --run-now في المشروع.
تتوقف المهمة بعد إغلاق الطرفيةكنت تعتمد على schedule داخل عملية انتهت؛ استخدم جدول النظام لتشغيل سكربت مستقل.
Task Scheduler يعمل دون إنشاء ملف السجلتحقق من python.exe، والمسارات المطلقة، والحساب، وStart in، ونتيجة التنفيذ الأخيرة.
cron لا يعثر على المكتباتغالبًا يستخدم مفسّرًا أو بيئة مختلفة؛ حدّد المسار المطلق لـ Python المطلوب.
اختلاف ساعة التنفيذتحقق من توقيت نظام التشغيل وإعدادات المنطقة الزمنية والتوقيت الصيفي.
لم تُنفذ مهام فائتة بعد عودة البرنامجrun_pending() لا يعيد تشغيل كل المواعيد التي فاتت أثناء توقف العملية.

للمزيد راجع الأسئلة الشائعة الرسمية لمكتبة schedule وشرح أوامر بايثون الأساسية للمبتدئين لتقوية مهارات تشغيل الأكواد من الطرفية.

الأسئلة الشائعة عن تشغيل سكربت بايثون تلقائيًا

كيف أشغّل سكربت بايثون كل ساعة؟

إذا كان برنامج بايثون سيظل مفتوحًا، استخدم schedule.every().hour.do(job) مع حلقة run_pending(). وإذا أردت تشغيل سكربت مستقل من نظام التشغيل، فأنشئ جدولًا كل ساعة في Task Scheduler أو cron.

هل مكتبة schedule تعمل بدون إنترنت؟

نعم، بعدما تثبّتها، تعمل المكتبة محليًا دون الحاجة إلى الإنترنت لأداء الجدولة نفسها. لكن المهمة التي تكتبها قد تحتاج اتصالًا إذا كانت تتواصل مع موقع أو API.

هل يمكن تشغيل سكربت بايثون في وقت محدد والكمبيوتر مطفأ؟

لا؛ الجهاز المطفأ لا ينفذ البرامج. بعض إعدادات Windows أو أنظمة التشغيل قد تسمح بتشغيل المهمة عند الاستيقاظ أو بعد عودة الجهاز، لكن ذلك يختلف عن تنفيذها أثناء انقطاع التشغيل.

لماذا لا تعمل مهمة schedule بعد إغلاق نافذة CMD؟

لأن الوظائف المجدولة بهذا الأسلوب موجودة في ذاكرة عملية بايثون. إذا انتهت العملية انتهت الحلقة. استخدم مدير عمليات مناسبًا أو جدولة النظام حسب حاجتك.

ما الفرق بين schedule وcron؟

schedule ينفذ الدوال أثناء تشغيل برنامج بايثون؛ أما cron فيطلق برنامجًا مستقلًا وفق جدول يحدده نظام Linux.

ما الملفات التي سأحصل عليها في حزمة الدرس؟

ستجد first_schedule.py وdaily_hourly.py وschedule_demo.py وtask_once.py وmultiple_jobs.py، مع دليل الإعداد لويندوز ولينكس، وملف المتطلبات، واختبارات وحدات. لا تحتوي الحزمة على كلمات مرور أو رموز وصول.

إرسال تعليق

أحدث أقدم