Python script'ini cron ile çalıştırmak; rapor üretimi, API senkronu, dosya temizliği veya veri aktarımı gibi işleri dakikadan aylık aralığa kadar otomatikleştirmenin en yaygın yoludur. İnteraktif shell'de çalışan komutun cron'da düşmesinin nedeni neredeyse her zaman ortam farkıdır: dar PATH, yanlış yorumlayıcı veya sanal ortam (venv) paketlerinin görünmemesi.
Bu rehber Linux/macOS crontab ile Python 3 kullanımını, venv ve Conda yollarını, gerçek hata mesajlarını ve uygulama içi zamanlayıcıları (APScheduler, schedule) kapsar. Django'da dağıtık periyodik görevler için Django Celery Beat daha uygundur; burada odak klasik script + sistem cron'dur.
Zaman ifadelerini doğrulamak için crontab guru veya cron ifadeleri rehberini kullanabilirsiniz. Üretimde her satırı eklemeden önce aynı kullanıcıyla env -i benzeri temiz ortamda komutu denemek, cron'un göreceği ortamı yaklaşık olarak simüle eder.
Ortam Değişkenleri ve Gizliler
Cron, etkileşimli shell profilinizi (.bashrc, .profile) yüklemez. Veritabanı URL'si, API anahtarı veya PYTHONPATH gibi değerler shell'de varken crontab'ta boş gelebilir. Üç güvenli yaklaşım vardır: değerleri crontab dosyasının üstünde KEY=deger satırlarıyla tanımlamak, script içinde python-dotenv ile proje kökündeki .env dosyasını okumak veya systemd/timer kullanıyorsanız unit dosyasında EnvironmentFile= vermek.
Gizli değerleri crontab satırına düz metin yapıştırmak yerine dosya izinleri kısıtlı bir env dosyası tercih edin (chmod 600). Log'a asla bağlantı dizgesi veya token yazmayın; hata mesajlarını temizleyin. Aynı script'i birden fazla sunucuda çalıştırıyorsanız çakışmayı önlemek için dağıtık kilit (Redis, PostgreSQL advisory lock) veya tek lider seçimi planlayın.
Adım Adım Crontab Kurulumu
- Projede venv oluşturun ve bağımlılıkları kurun:
python3 -m venv venv && venv/bin/python -m pip install -r requirements.txt. - Yorumlayıcı yolunu alın:
venv/bin/python(veyawhich pythonaktive edilmiş shell'de). Activate etmek cron için şart değildir; mutlak yol yeterlidir. - Aynı komutu elle çalıştırın:
/home/kullanici/proje/venv/bin/python /home/kullanici/proje/rapor.py. Çıkış kodu 0 olmalı. crontab -eile satırı ekleyin; stdout/stderr'i log dosyasına yönlendirin.- Göreli dosya yolları kullanıyorsanız satırın başına
cd /home/kullanici/proje &&koyun. - İlk çalışmadan sonra log'u okuyun. Sessiz başarısızlıklarda cron mail'i çoğu sunucuda boştur; log şarttır.
# Sistem Python (paketsiz basit script)
0 */6 * * * /usr/bin/python3 /home/kullanici/scripts/rapor.py >> /var/log/rapor.log 2>&1
# venv (önerilen)
0 */6 * * * /home/kullanici/proje/venv/bin/python /home/kullanici/proje/rapor.py >> /var/log/rapor.log 2>&1
# Çalışma dizini sabit
0 */6 * * * cd /home/kullanici/proje && /home/kullanici/proje/venv/bin/python rapor.py >> /var/log/rapor.log 2>&1
# Conda
0 */6 * * * /home/kullanici/miniconda3/envs/myenv/bin/python /home/kullanici/proje/rapor.py
/bin/sh'dir. source venv/bin/activate bash builtin'idir; gerekirse crontab başına SHELL=/bin/bash yazın. En temiz yöntem yine de venv/bin/python yoludur.Python Cron Script Yazma
Logging'i hem dosyaya hem stdout'a yazın; cron yönlendirmesi stdout'u yakalar. Kritik hatalarda sys.exit(1) dönün ki izleme araçları başarısızlığı ayırt edebilsin.
#!/usr/bin/env python3
"""Günlük veri özeti — zamanlama: 0 6 * * *"""
import json
import logging
import sys
from datetime import datetime, timedelta
from pathlib import Path
BASE = Path(__file__).resolve().parent
(BASE / "logs").mkdir(parents=True, exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler(BASE / "logs" / "veri-analiz.log"),
logging.StreamHandler(sys.stdout),
],
)
logger = logging.getLogger(__name__)
def ana_gorev() -> None:
logger.info("Analiz başladı")
try:
import pandas as pd
import sqlalchemy
engine = sqlalchemy.create_engine(
"mysql+pymysql://user:pass@127.0.0.1/db"
)
dun = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
df = pd.read_sql(
"SELECT * FROM siparisler WHERE DATE(tarih) = %(d)s",
engine,
params={"d": dun},
)
ozet = {
"tarih": dun,
"toplam_siparis": int(len(df)),
"toplam_gelir": float(df["tutar"].sum()) if len(df) else 0.0,
}
out = BASE / "raporlar" / f"rapor-{dun}.json"
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(ozet, ensure_ascii=False, indent=2), encoding="utf-8")
logger.info("Rapor yazıldı: %s", out)
except Exception:
logger.exception("Analiz başarısız")
sys.exit(1)
if __name__ == "__main__":
ana_gorev()
Gerçek Senaryolar
Senaryo 1: Kur / fiyat senkronu (her 30 dakika)
Harici API'den kur çeker, JSON dosyasına yazar. Ağ hatalarında exception yakalanır; bir sonraki koşuda yeniden denenir. Zamanlama: */30 * * * *. Timeout koyun (requests.get(..., timeout=30)); aksi halde asılı kalan süreçler üst üste binebilir. HTML sayfa tarama, robots.txt ve ETag ile değişiklik algılama için cron ile web scraping rehberindeki hız limiti kurallarını aynı venv içine taşıyabilirsiniz.
*/30 * * * * /home/kullanici/proje/venv/bin/python /home/kullanici/proje/doviz.py >> /var/log/doviz.log 2>&1
Senaryo 2: Gece CSV arşivi (02:30)
Veritabanından dünkü satırları okur, gzip'li CSV üretir, eski arşivleri siler. Yoğun saatlerden kaçınmak için 30 2 * * *. Büyük export'larda bellek için chunk/iterator kullanın; tek seferde milyon satır DataFrame'e yüklemeyin. İş süresinin zaman aralığını aşabileceğini düşünüyorsanız dosya kilidi (fcntl.flock veya portalocker) ekleyin; aksi halde ikinci süreç aynı dosyaya yazmaya çalışır.
Arşiv dosyalarını nesne depolama veya yedek diske taşıyorsanız ağ kesintisini yeniden denenebilir hale getirin: geçici ada yazın, doğrulayın, sonra atomik rename yapın. Başarı log'unda satır sayısı ve dosya boyutunu yazmak, boş arşiv üretimini erken fark etmenizi sağlar.
Uygulama İçi Zamanlayıcılar
Python dışı çalışma zamanlarında benzer ihtiyaçlar farklı araçlarla çözülür: Node.js için Node.js cron job (node-cron veya sistem crontab), derlenmiş ikili için Go cron job örnekleri venv yoluna denk düşen mutlak binary çağrısı kullanır. Aşağıdaki kütüphaneler ise sürecin içinde kalan zamanlayıcılardır.
APScheduler
Sürekli çalışan bir süreç içinde cron benzeri ifadeler için uygundur. Süreç ölürse zamanlama da durur; bu yüzden systemd/PM2 ile process yönetimi gerekir.
from apscheduler.schedulers.blocking import BlockingScheduler
scheduler = BlockingScheduler(timezone="Europe/Istanbul")
@scheduler.scheduled_job("cron", hour=3, minute=0)
def gunluk_yedek():
print("Yedek alınıyor")
@scheduler.scheduled_job("interval", minutes=15)
def saglik_kontrol():
print("Sağlık kontrolü")
scheduler.start()
python-crontab ve schedule
python-crontab, deploy sırasında sistem crontab'ına satır eklemek için kullanılır. schedule kütüphanesi ise basit in-process döngüdür; production'da genelde sistem cron veya Celery tercih edilir.
from crontab import CronTab
cron = CronTab(user=True)
job = cron.new(command="/home/kullanici/proje/venv/bin/python /home/kullanici/proje/yedek.py")
job.setall("0 3 * * *")
job.set_comment("Gunluk yedek")
cron.write()
Sık Hatalar ve Çözümleri
/bin/sh: 1: python3: not found
Neden: Cron PATH'i dar. Çözüm: /usr/bin/python3 veya venv yolu.
ModuleNotFoundError: No module named 'requests'
Neden: Sistem Python'u çağrıldı; paket venv'de. Çözüm: .../venv/bin/python kullanın; kurulumu venv/bin/python -m pip install ... ile yapın.
PermissionError: [Errno 13] Permission denied: '/var/log/...'
Neden: Crontab kullanıcısının yazma hakkı yok. Çözüm: Log'u home veya proje altına alın; dizin izinlerini düzeltin.
FileNotFoundError: [Errno 2] No such file or directory: 'data/out.csv'
Neden: Göreli yol, cwd home. Çözüm: Path(__file__).resolve().parent veya crontab'ta cd.
ssl.SSLCertVerificationError / bağlantı zaman aşımı
Neden: Ağ, proxy veya eksik CA. Çözüm: timeout ekleyin, sertifika zincirini kontrol edin; doğrulamayı kapatmak yerine kök nedeni düzeltin.
cronjob.com.tr ile HTTP Alternatifi
Script'iniz bir HTTP uç noktası olarak tetiklenebiliyorsa (ör. Flask/FastAPI içinde korumalı /internal/cron/rapor), sunucu crontab'ı yerine cronjob.com.tr kullanabilirsiniz. Ücretsizdir, kredi kartı istemez; en kısa aralık 1 dakikadır.
- Endpoint'i gizli header token veya HTTP Basic Auth ile koruyun; başarıda 200–399 dönün.
- Panelde URL, metot, header ve zamanlamayı girin (hazır aralık veya 5 alanlı cron; saat dilimi iş bazında).
- Timeout: aralığa göre (1 dk → 55 sn, 5 dk+ → 290 sn). TLS sertifikası doğrulanır; localhost/özel IP'lere istek gitmez.
- Ardışık hatalarda e-posta bildirimi; her çalışmada durum, süre ve yanıt özeti 7 gün loglanır.
Saf dosya sistemi / veritabanı batch işi sunucu içinde kalmalıdır; bu durumda sistem cron veya worker kullanın. Linux cron ve çalışmıyor teşhisi yardımcı olur.
Sıkça Sorulan Sorular (SSS)
Virtual environment cron'da neden zorunlu gibi davranır?
Paketler venv içine kurulur. Cron sistem Python'unu çağırırsa ModuleNotFoundError alırsınız. venv içindeki python ikilisinin mutlak yolunu kullanın; activate şart değildir.
APScheduler mı yoksa sistem cron mu?
Sabit batch işler için sistem cron daha dayanıklıdır; süreç çökse bile bir sonraki planlanan tetiklemede yeniden başlar. Uygulama içi dinamik zamanlama için APScheduler uygundur.
Cron'da source venv/bin/activate neden kırılır?
Cron'un varsayılan kabuğu /bin/sh'dir ve source builtin'i yoktur. SHELL=/bin/bash yazın veya doğrudan venv/bin/python yolunu kullanın.
Relative path ve cwd sorununu nasıl çözerim?
Script'te Path(__file__).resolve().parent kullanın veya crontab'ta cd /proje && ... ile çalışma dizinini sabitleyin.
Django yönetimi cron'dan nasıl çağrılır?
venv python ile manage.py komutunu çalıştırın. Periyodik Celery Beat ihtiyacı için django-celery-beat rehberine bakın.
Hemen Ücretsiz Cron Job Oluşturun
HTTP ile tetiklenen Python işlerinizi cronjob.com.tr üzerinden zamanlayın. Ücretsiz, kredi kartı yok; log ve hata bildirimi dahil.
Ücretsiz Başla →