매일 새벽 3시에 노션 페이지가 자동으로 백업되는 시스템 만들기

노션에 열심히 작성한 내용이 갑자기 사라진다면 정말 막막할 거예요. 실수로 페이지를 삭제하거나 서버 문제가 생기면 소중한 데이터를 잃을 수 있어요. 그래서 로컬 컴퓨터에 정기적으로 백업하는 자동화 시스템을 만들어 보려고 해요.


Mac에서 Notion API를 이용하면 매일 자동으로 백업이 실행되도록 설정할 수 있어요. 파이썬 스크립트 하나와 Mac의 기본 기능을 조합하면 돼요.




Notion API 토큰 발급받기


먼저 Notion 개발자 센터에 접속해서 Internal Integration을 만들어야 해요. https://www.notion.com/my-integrations 에서 새 통합을 생성하고 API 토큰을 복사해 두세요.


백업하려는 노션 페이지에서 오른쪽 상단 점 세 개 메뉴를 클릭해요. 공유 메뉴에서 방금 만든 Integration을 추가하면 API가 해당 페이지에 접근할 수 있게 돼요.


파이썬 백업 스크립트 작성하기


터미널을 열고 필요한 라이브러리부터 설치해요:


pip3 install requests
pip3 install notion-client


이제 백업 스크립트를 만들어볼게요. 홈 디렉토리에 notion_backup.py 파일을 생성해요:


import requests
import json
import os
from datetime import datetime

# API 토큰과 페이지 ID 설정
NOTION_TOKEN = "secret_여기에_토큰_입력"
PAGE_ID = "페이지ID_입력"
BACKUP_DIR = "/Users/사용자명/Documents/NotionBackup"

# 백업 디렉토리 생성
if not os.path.exists(BACKUP_DIR):
    os.makedirs(BACKUP_DIR)

headers = {
    "Authorization": f"Bearer {NOTION_TOKEN}",
    "Notion-Version": "2022-06-28",
    "Content-Type": "application/json"
}

# 페이지 데이터 가져오기
def backup_page(page_id):
    url = f"https://api.notion.com/v1/pages/{page_id}"
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        # 날짜별 파일명 생성
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{BACKUP_DIR}/notion_backup_{timestamp}.json"
        
        # JSON 파일로 저장
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(response.json(), f, ensure_ascii=False, indent=4)
        
        print(f"백업 완료: {filename}")
        return True
    else:
        print(f"백업 실패: {response.status_code}")
        return False

# 데이터베이스 백업 함수
def backup_database(database_id):
    url = f"https://api.notion.com/v1/databases/{database_id}/query"
    all_results = []
    has_more = True
    start_cursor = None
    
    while has_more:
        payload = {}
        if start_cursor:
            payload["start_cursor"] = start_cursor
            
        response = requests.post(url, headers=headers, json=payload)
        
        if response.status_code == 200:
            data = response.json()
            all_results.extend(data.get("results", []))
            has_more = data.get("has_more", False)
            start_cursor = data.get("next_cursor")
        else:
            print(f"데이터베이스 조회 실패: {response.status_code}")
            break
    
    # 결과 저장
    if all_results:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{BACKUP_DIR}/database_backup_{timestamp}.json"
        
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(all_results, f, ensure_ascii=False, indent=4)
        
        print(f"데이터베이스 백업 완료: {filename}")

# 실행
if __name__ == "__main__":
    backup_page(PAGE_ID)
    # 데이터베이스도 백업하려면 아래 주석 해제
    # backup_database("데이터베이스_ID")


Markdown 형식으로 변환하여 저장하기


JSON 파일보다 읽기 편한 Markdown 형식으로도 저장할 수 있어요. notion-to-md 라이브러리를 활용하면 간단해요:


npm install -g notion-to-md


Python 스크립트에 Markdown 변환 기능을 추가해볼게요:


import subprocess

def convert_to_markdown(page_id):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    output_dir = f"{BACKUP_DIR}/markdown_{timestamp}"
    
    # notion-to-md 명령 실행
    cmd = [
        "notion-to-md",
        "-t", NOTION_TOKEN,
        "-p", page_id,
        "-o", output_dir
    ]
    
    try:
        subprocess.run(cmd, check=True)
        print(f"Markdown 변환 완료: {output_dir}")
    except subprocess.CalledProcessError:
        print("Markdown 변환 실패")

# 메인 함수에 추가
if __name__ == "__main__":
    backup_page(PAGE_ID)
    convert_to_markdown(PAGE_ID)


crontab으로 자동 실행 설정하기


이제 매일 새벽 3시에 자동으로 실행되도록 설정해요. 터미널에서 crontab 편집기를 열어요:


crontab -e


다음 줄을 추가하면 매일 새벽 3시에 백업이 실행돼요:


0 3 * * * /usr/local/bin/python3 /Users/사용자명/notion_backup.py >> /Users/사용자명/backup_log.txt 2>&1


crontab 설정이 어렵다면 Mac의 launchd를 사용할 수도 있어요. ~/Library/LaunchAgents/ 폴더에 com.user.notionbackup.plist 파일을 만들어요:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.notionbackup</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/python3</string>
        <string>/Users/사용자명/notion_backup.py</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>3</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/Users/사용자명/backup_log.txt</string>
    <key>StandardErrorPath</key>
    <string>/Users/사용자명/backup_error.txt</string>
</dict>
</plist>


plist 파일을 만든 후 다음 명령으로 활성화해요:


launchctl load ~/Library/LaunchAgents/com.user.notionbackup.plist


클라우드에 자동 업로드하기


로컬 백업만으로는 하드디스크 고장 시 위험해요. Google Drive나 Dropbox에도 자동으로 업로드하는 기능을 추가해볼게요:


import shutil
from pathlib import Path

def upload_to_cloud():
    # Dropbox 동기화 폴더 경로
    dropbox_path = "/Users/사용자명/Dropbox/NotionBackup"
    
    if not os.path.exists(dropbox_path):
        os.makedirs(dropbox_path)
    
    # 최신 백업 파일 복사
    backup_files = sorted(Path(BACKUP_DIR).glob("*.json"))
    if backup_files:
        latest_file = backup_files[-1]
        shutil.copy2(latest_file, dropbox_path)
        print(f"클라우드 업로드 완료: {latest_file.name}")


백업 상태 알림 받기


백업이 제대로 실행됐는지 확인하는 알림 기능도 추가할 수 있어요. Mac의 알림 센터를 활용해볼게요:


def send_notification(title, message):
    cmd = f'''
    osascript -e 'display notification "{message}" with title "{title}"'
    '''
    os.system(cmd)

# 백업 함수 수정
def backup_page(page_id):
    # ... 기존 코드 ...
    
    if response.status_code == 200:
        # ... 저장 코드 ...
        send_notification("Notion 백업 성공", f"백업 파일: {filename}")
        return True
    else:
        send_notification("Notion 백업 실패", f"오류 코드: {response.status_code}")
        return False


오래된 백업 파일 자동 삭제


백업 파일이 계속 쌓이면 용량 문제가 생길 수 있어요. 30일 이상 된 파일은 자동으로 삭제하는 기능을 추가해요:


from datetime import timedelta

def cleanup_old_backups(days=30):
    cutoff_date = datetime.now() - timedelta(days=days)
    
    for file_path in Path(BACKUP_DIR).glob("*.json"):
        file_time = datetime.fromtimestamp(file_path.stat().st_mtime)
        
        if file_time < cutoff_date:
            file_path.unlink()
            print(f"오래된 백업 삭제: {file_path.name}")

# 메인 함수에 추가
if __name__ == "__main__":
    backup_page(PAGE_ID)
    convert_to_markdown(PAGE_ID)
    upload_to_cloud()
    cleanup_old_backups()


여러 페이지 한 번에 백업하기


하나의 페이지만 백업하는 게 아니라 여러 페이지를 한 번에 백업하려면 페이지 ID 리스트를 만들어요:


# 백업할 페이지 리스트
PAGES_TO_BACKUP = [
    {"id": "페이지ID1", "name": "프로젝트_노트"},
    {"id": "페이지ID2", "name": "일일_업무"},
    {"id": "페이지ID3", "name": "아이디어_메모"}
]

def backup_all_pages():
    for page in PAGES_TO_BACKUP:
        print(f"\n{page['name']} 백업 시작...")
        
        # 각 페이지별 폴더 생성
        page_dir = f"{BACKUP_DIR}/{page['name']}"
        if not os.path.exists(page_dir):
            os.makedirs(page_dir)
        
        # 백업 실행
        backup_page(page['id'])


실제로 사용하다 보면 Notion API의 속도 제한에 걸릴 수 있어요. 너무 빠르게 많은 요청을 보내면 일시적으로 차단될 수 있으니 각 요청 사이에 약간의 대기 시간을 넣는 게 좋아요:


import time

def backup_with_delay():
    for page in PAGES_TO_BACKUP:
        backup_page(page['id'])
        time.sleep(2)  # 2초 대기


Mac에서 이런 자동화 시스템을 구축하면 Notion 데이터를 안전하게 보호할 수 있어요. 중요한 건 정기적으로 백업이 제대로 실행되고 있는지 확인하는 거예요. 가끔 backup_log.txt 파일을 열어서 오류가 없는지 체크해 보세요.


맥에서 Git 커밋 전에 코드 스타일 자동으로 검사하는 방법