Python 작업 스케줄링 | 자동화 작업 예약 완벽 정리

Python 작업 스케줄링 | 자동화 작업 예약 완벽 정리

이 글의 핵심

Python 작업 스케줄링에 대해 정리한 개발 블로그 글입니다. schedule.every().day.at("09:00").do(job) 개념과 예제 코드를 단계적으로 다루며, 실무·학습에 참고할 수 있도록 구성했습니다. 관련 키워드: Python, 스케줄링, 자동화, schedule, cron.

들어가며

배치 스크립트나 서버 안에서 주기적으로 작업을 돌리려면, 단순 while 루프보다 스케줄 라이브러리나 OS 스케줄러와 맞추는 편이 안전합니다. 이 글을 끝까지 읽으면 Python에서 반복 실행을 설계할 때 선택지를 비교하고, 예제를 자신의 프로젝트에 옮길 수 있습니다.

”작업을 자동으로 실행하기”

작업 스케줄링은 정해진 시간에 자동으로 작업을 실행하는 기술입니다.


1. schedule 라이브러리

설치

pip install schedule

기본 사용

import schedule
import time

def job():
    print("작업 실행!")

# 10초마다
schedule.every(10).seconds.do(job)

# 1분마다
schedule.every(1).minutes.do(job)

# 매일 오전 9시
schedule.every().day.at("09:00").do(job)

# 매주 월요일 오전 10시
schedule.every().monday.at("10:00").do(job)

# 실행
while True:
    schedule.run_pending()
    time.sleep(1)

2. 실전 예제

자동 백업 스크립트

import schedule
import time
from datetime import datetime
import shutil
from pathlib import Path

def backup_files():
    """파일 백업"""
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    backup_name = f"backup_{timestamp}"
    
    source = Path('./data')
    backup_dir = Path('./backups')
    backup_dir.mkdir(exist_ok=True)
    
    backup_path = backup_dir / backup_name
    shutil.copytree(source, backup_path)
    
    print(f"[{datetime.now()}] 백업 완료: {backup_name}")

# 매일 자정에 백업
schedule.every().day.at("00:00").do(backup_files)

# 매주 일요일 오후 11시에 백업
schedule.every().sunday.at("23:00").do(backup_files)

print("백업 스케줄러 시작...")
while True:
    schedule.run_pending()
    time.sleep(60)

3. APScheduler

설치

pip install apscheduler

고급 스케줄링

from apscheduler.schedulers.blocking import BlockingScheduler
from datetime import datetime

scheduler = BlockingScheduler()

def job1():
    print(f"[{datetime.now()}] Job 1 실행")

def job2():
    print(f"[{datetime.now()}] Job 2 실행")

# Cron 스타일
scheduler.add_job(job1, 'cron', hour=9, minute=0)  # 매일 9시

# 간격
scheduler.add_job(job2, 'interval', minutes=30)  # 30분마다

# 특정 시간
scheduler.add_job(
    job1,
    'cron',
    day_of_week='mon-fri',
    hour=9,
    minute=0
)

scheduler.start()

4. 웹 스크래핑 자동화

주기적 데이터 수집

import schedule
import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime

def scrape_prices():
    """상품 가격 수집"""
    urls = [
        'https://shop1.com/product/123',
        'https://shop2.com/product/456'
    ]
    
    prices = []
    
    for url in urls:
        try:
            response = requests.get(url, timeout=10)
            soup = BeautifulSoup(response.text, 'html.parser')
            
            price = soup.select_one('.price').text
            price = int(price.replace(',', '').replace('원', ''))
            
            prices.append({
                'url': url,
                'price': price,
                'timestamp': datetime.now()
            })
        except Exception as e:
            print(f"에러: {url} - {e}")
    
    # CSV에 추가
    df = pd.DataFrame(prices)
    df.to_csv('price_history.csv', mode='a', header=False, index=False)
    print(f"[{datetime.now()}] 가격 수집 완료")

# 1시간마다 실행
schedule.every(1).hours.do(scrape_prices)

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

5. 이메일 알림

자동 리포트 발송

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import schedule

def send_daily_report():
    """일일 리포트 이메일 발송"""
    # 리포트 생성
    report = generate_report()
    
    # 이메일 설정
    msg = MIMEMultipart()
    msg['From'] = '[email protected]'
    msg['To'] = '[email protected]'
    msg['Subject'] = f"일일 리포트 - {datetime.now().strftime('%Y-%m-%d')}"
    
    msg.attach(MIMEText(report, 'html'))
    
    # 발송
    try:
        server = smtplib.SMTP('smtp.gmail.com', 587)
        server.starttls()
        server.login('[email protected]', 'password')
        server.send_message(msg)
        server.quit()
        print("리포트 발송 완료")
    except Exception as e:
        print(f"발송 실패: {e}")

def generate_report():
    """리포트 HTML 생성"""
    return """
    <html>
        <body>
            <h1>일일 리포트</h1>
            <p>총 매출: 1,000,000원</p>
            <p>신규 고객: 50명</p>
        </body>
    </html>
    """

# 매일 오전 8시에 발송
schedule.every().day.at("08:00").do(send_daily_report)

6. 백그라운드 실행

Windows 작업 스케줄러

# Python 스크립트를 Windows 작업 스케줄러에 등록
# 1. 작업 스케줄러 열기
# 2. 기본 작업 만들기
# 3. 프로그램: python.exe
# 4. 인수: C:\path\to\script.py

Linux cron

# crontab 편집
crontab -e

# 매일 오전 9시
0 9 * * * /usr/bin/python3 /path/to/script.py

# 매시간
0 * * * * /usr/bin/python3 /path/to/script.py

# 매주 월요일 오전 10시
0 10 * * 1 /usr/bin/python3 /path/to/script.py

로깅·예외·타임아웃으로 스케줄 작업 운영하기

while True 안에서 run_pending을 도는 방식은 알람을 맞춰 두고 정해진 함수만 반복 호출하는 시계와 비슷합니다. 장시간 돌리려면 로그 파일으로 실행 여부를 남기고, 작업 안에서 예외를 삼켜 버리지 말고 기록하며, 오래 걸리는 작업에는 타임아웃(환경에 따라 signal 등)을 검토합니다.

# ✅ 로깅 추가
import logging

logging.basicConfig(
    filename='scheduler.log',
    level=logging.INFO,
    format='%(asctime)s - %(message)s'
)

def job():
    logging.info("작업 시작")
    # 작업 수행
    logging.info("작업 완료")

# ✅ 에러 처리
def safe_job():
    try:
        job()
    except Exception as e:
        logging.error(f"에러: {e}")

# ✅ 타임아웃 설정
import signal

def timeout_handler(signum, frame):
    raise TimeoutError("작업 시간 초과")

signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(300)  # 5분 제한

정리

핵심 요약

  1. schedule: 간단한 스케줄링
  2. APScheduler: 고급 스케줄링
  3. cron: Linux/Mac 시스템 스케줄러
  4. 자동화: 백업, 스크래핑, 리포트
  5. 모니터링: 로깅, 에러 처리

추천 활용

  • 자동 백업
  • 가격 모니터링
  • 데이터 수집
  • 리포트 생성
  • 알림 발송

관련 글