파이썬 자동화 #1 반복 작업 끝내기: 스크립트 첫걸음과 파일 정리
다운로드 폴더를 열어보면 스크린샷, 설치 파일, PDF 청구서, 압축 파일이 몇 달치씩 쌓여 있습니다. 한 번 정리하는 데 10분, 일주일이면 또 원상복구입니다. 이런 반복 작업이야말로 파이썬이 가장 빨리 보답하는 영역입니다. 이 시리즈는 파이썬 문법 기초만 아는 사람이 실제로 돌아가는 자동화 스크립트를 손에 쥐는 것을 목표로 합니다. 모던 파이썬 기초를 끝낸 수준이면 충분하고, 직장인이 업무 틈틈이 따라 하기에도 무리가 없는 분량으로 구성하겠습니다. 전체 7편의 지도는 다음과 같습니다.
- #1 반복 작업 끝내기: 스크립트 첫걸음과 파일 정리 ← 이번 글
- #2 엑셀 자동화: openpyxl로 반복 보고서 처리
- #3 웹 스크래핑 기초: 정적 페이지에서 데이터 모으기
- #4 웹 스크래핑 심화: 동적 페이지 다루기
- #5 메일과 알림: 결과를 자동으로 받아보기
- #6 스케줄링: 매일 알아서 돌아가게 만들기
- #7 CLI 도구로 포장: 시리즈 마무리
자동화 스크립트의 모양 #
자동화 스크립트는 웹 서비스나 라이브러리와 다르게 생겼습니다. 파일 하나, 위에서 아래로 읽히는 흐름, 그리고 맨 아래의 if __name__ == "__main__": 진입점. 이 단순한 구조가 기본형입니다. 진입점 블록의 역할은 하나로, 이 파일을 직접 실행했을 때만 아래 코드를 돌리라는 표시입니다. 이 블록이 없으면 다른 스크립트에서 함수만 가져다 쓰려고 import 하는 순간 정리가 실행돼 버립니다. 자동화 스크립트는 재사용할 일이 자주 생기므로 처음부터 이 모양으로 쓰는 습관을 들이는 편이 좋습니다. 구체적인 모습은 아래 완성 예제에서 보겠습니다.
실행하는 방법 #
이번 글의 코드는 표준 라이브러리만 사용하므로 설치할 패키지가 없습니다. 파이썬이 설치돼 있다면 터미널에서 python organize.py로 실행하면 되고, 모던 파이썬 기초 1편에서 다룬 uv를 쓰고 있다면 uv run organize.py로 실행해도 결과는 같습니다. uv run 쪽의 장점은 나중에 외부 패키지가 필요해졌을 때 드러납니다. 스크립트 상단에 의존성을 적어두면 uv가 임시 환경을 알아서 구성해 주므로, 가상환경 관리 없이 스크립트 한 파일만 들고 다닐 수 있습니다.
완성 예제: 다운로드 폴더 정리기 #
파일을 다루는 표준 도구는 pathlib입니다. 경로를 문자열이 아니라 객체로 다루기 때문에 운영체제가 달라도 같은 코드가 동작합니다. 필요한 동작은 세 가지입니다. iterdir()로 폴더 안 항목을 순회하고, suffix로 확장자를 읽고, rename()으로 옮깁니다.
from pathlib import Path
RULES = {
"images": {".jpg", ".jpeg", ".png", ".gif", ".webp"},
"docs": {".pdf", ".docx", ".xlsx", ".pptx", ".txt"},
"archives": {".zip", ".tar", ".gz", ".7z"},
"installers": {".dmg", ".pkg", ".exe", ".msi"},
}
def category_for(item: Path) -> str | None:
for name, exts in RULES.items():
if item.suffix.lower() in exts:
return name
return None # 규칙에 없는 확장자는 건드리지 않음
def organize(target: Path) -> None:
for item in target.iterdir():
if not item.is_file():
continue
category = category_for(item)
if category is None:
continue
dest_dir = target / category
dest_dir.mkdir(exist_ok=True)
item.rename(dest_dir / item.name)
print(f"{item.name} -> {category}/")
if __name__ == "__main__":
organize(Path.home() / "Downloads")흐름은 단순합니다. 폴더 안 파일을 하나씩 보고, 확장자가 규칙에 있으면 해당 폴더를 만들어 옮깁니다. mkdir(exist_ok=True)는 폴더가 이미 있어도 에러를 내지 않는 옵션이고, suffix.lower()는 .PDF처럼 대문자 확장자도 같은 규칙으로 잡기 위한 처리입니다. 규칙에 없는 확장자는 그대로 두므로, 모르는 파일을 엉뚱한 곳으로 옮길 걱정은 없습니다.
실수 방지: dry-run과 덮어쓰기 #
파일을 옮기는 스크립트는 한 번 잘못 돌리면 되돌리기 어렵습니다. 그래서 안전장치 두 개를 먼저 달아야 합니다. 첫 번째는 dry-run 모드입니다. 실제로 옮기지 않고 무엇을 어디로 옮길 계획인지 출력만 하는 모드로, 새 폴더에 처음 돌릴 때 결과를 미리 확인할 수 있습니다. 두 번째는 덮어쓰기 방지입니다. 목적지에 같은 이름의 파일이 이미 있으면 rename이 기존 파일을 덮어쓸 수 있으므로, 같은 이름이 있으면 report (1).pdf처럼 번호를 붙여 피하겠습니다. 위 코드에서 organize만 다음과 같이 바꾸면 됩니다.
def unique_path(dest: Path) -> Path:
if not dest.exists():
return dest
for n in range(1, 1000):
candidate = dest.with_name(f"{dest.stem} ({n}){dest.suffix}")
if not candidate.exists():
return candidate
raise RuntimeError("사용할 수 있는 파일 이름이 없습니다")
def organize(target: Path, dry_run: bool = False) -> None:
for item in target.iterdir():
if not item.is_file():
continue
category = category_for(item)
if category is None:
continue
dest_dir = target / category
dest = unique_path(dest_dir / item.name)
if dry_run:
print(f"[계획] {item.name} -> {category}/{dest.name}")
continue
dest_dir.mkdir(exist_ok=True)
item.rename(dest)
print(f"{item.name} -> {category}/{dest.name}")dry_run=True로 호출하면 출력만 하고 멈춥니다. 파일을 건드리는 자동화는 계획을 먼저 보고, 확인한 뒤에 실행하는 이 순서가 기본입니다.
argparse로 대상 폴더 받기 #
지금은 다운로드 폴더가 코드 안에 고정돼 있습니다. 정리할 폴더를 실행할 때 인자로 넘기도록 argparse를 붙이겠습니다. 표준 라이브러리라 설치가 필요 없고, 도움말까지 자동으로 만들어 줍니다.
import argparse
def main() -> None:
parser = argparse.ArgumentParser(description="확장자별로 파일을 분류해 정리합니다")
parser.add_argument("target", type=Path, help="정리할 폴더 경로")
parser.add_argument("--dry-run", action="store_true", help="옮기지 않고 계획만 출력")
args = parser.parse_args()
organize(args.target, dry_run=args.dry_run)
if __name__ == "__main__":
main()type=Path를 지정했기 때문에 인자가 문자열이 아니라 Path 객체로 바로 들어옵니다. 이제 어떤 폴더든 대상으로 지정할 수 있고, --dry-run 플래그로 미리보기도 됩니다.
python organize.py ~/Downloads --dry-run # [계획] invoice.pdf -> docs/invoice.pdf
python organize.py ~/Downloads # invoice.pdf -> docs/invoice.pdf한 단계 응용: 날짜별 폴더와 오래된 파일 보관 #
확장자 분류에 익숙해지면 같은 패턴으로 변형을 만들 수 있습니다. 분류 기준을 확장자 대신 파일의 수정 시각으로 바꾸면 월별 정리기가 됩니다. organize 안의 category_for(item)를 다음 함수로 바꾸면 됩니다.
from datetime import datetime
def month_folder(item: Path) -> str:
mtime = datetime.fromtimestamp(item.stat().st_mtime)
return mtime.strftime("%Y-%m") # 2026-07 형태의 폴더 이름오래된 파일 보관도 같은 재료로 만들 수 있습니다. datetime.now() - timedelta(days=90)보다 수정 시각이 오래된 파일만 걸러 archive 폴더로 옮기면 보관 스크립트가 됩니다. 순회하고, 조건으로 거르고, 옮긴다는 한 가지 패턴에서 분류 기준만 갈아 끼우는 구조입니다. 이 패턴이 손에 익으면 파일을 다루는 자동화 대부분을 같은 틀로 만들 수 있습니다.
정리 #
이번 글에서 만든 것을 정리하겠습니다.
- 자동화 스크립트의 기본형: 한 파일, 위에서 아래로,
if __name__ == "__main__":진입점 pathlib의iterdir,suffix,rename으로 만든 다운로드 폴더 정리기와 dry-run,unique_path두 가지 안전장치argparse로 대상 폴더와 플래그를 인자로 받는 구조- 분류 기준만 바꿔 월별 정리, 오래된 파일 보관으로 확장하는 패턴
다음 글(#2 엑셀 자동화)에서는 직장인 반복 작업의 대표 격인 엑셀을 다루겠습니다. openpyxl로 여러 파일을 읽어 하나로 합치고, 서식을 입혀 보고서를 만들어내는 과정까지 진행하겠습니다.