
이 글은 화려한 자동화 프레임워크 소개가 아니라, 매일 반복되던 단순 업무를 파이썬으로 하나씩 걷어내면서 얻은 실무 팁 위주의 기록입니다. 코드 자체보다 "왜 이렇게 짜게 됐는지"에 초점을 맞췄습니다.
DB/ETL 업무를 하다 보면 정작 SQL이나 시스템 설계보다, 매일 반복되는 엑셀 취합이나 파일 정리 같은 잡무에 생각보다 많은 시간을 뺏깁니다. 저도 어느 순간부터 "이거 매번 손으로 하지 말고 스크립트로 짜두면 되는데"라는 생각이 쌓여서 파이썬으로 하나둘 자동화 스크립트를 만들기 시작했습니다. 검색해보면 판다스나 오픈파이엑셀 문법 강의는 많은데, 실제 사무직/현업 업무에서 자주 쓰이는 자잘한 자동화 패턴을 실무 예제로 정리한 글은 의외로 드물어서 이 글을 써보게 됐습니다. 왜 업무자동화를 파이썬으로 시작했는지, 그리고 처음 마주친 현실적인 벽 처음 자동화를 시작한 계기는 단순했습니다. 매일 여러 부서에서 넘어오는 엑셀 파일들을 하나로 취합해서 특정 양식으로 다시 정리하는 작업을 반복하고 있었는데, 파일 이름 규칙이 부서마다 조금씩 다르고, 시트 구성도 미묘하게 달라서 "완전 자동화"가 생각보다 훨씬 까다로웠습니다. 처음엔 "판다스로 다 읽어서 합치면 끝이겠지"라고 가볍게 생각했는데, 실제로는 예외 케이스를 하나씩 처리하는 데 훨씬 많은 시간이 들었습니다. 두 번째 벽은 엑셀 파일 자체의 특성이었습니다. 병합된 셀, 숨겨진 행/열, 서식이 깨진 날짜 값, 사람이 손으로 입력하다가 생긴 오탈자와 공백 등, 데이터베이스처럼 깔끔하게 정제된 데이터가 아니라는 걸 실감했습니다. 특히 날짜 컬럼이 문자열로 들어있는 경우와 실제 날짜 타입으로 들어있는 경우가 파일마다 섞여 있어서, 이걸 구분하지 않고 일괄 처리하다가 데이터가 밀리는 사고를 겪은 적도 있습니다. 세 번째는 자동화 스크립트에 대한 주변의 신뢰 문제였습니다. 처음 자동화 스크립트로 만든 취합 결과를 공유했을 때, "이거 사람이 직접 확인 안 하고 그냥 믿어도 되는 거냐"는 반응이 많았습니다. 결국 자동화 자체보다, 결과가 맞다는 걸 증명하는 검증 로직과 로그를 같이 만들어서 신뢰를 쌓는 과정이 기술적인 부분 못지않게 중요했습니다. 네 번째는 실행 환경 문제였습니다. 제 컴퓨터에서는 잘 돌던 스크립트가 다른 담당자 PC에서는 패키지 버전 차이나 경로 문제로 그대로 실행되지 않는 경우가 종종 있었습니다. 처음엔 "코드는 똑같은데 왜 안 되지"라며 당황했는데, 결국 실행 환경 자체를 문서화하거나 최소한의 배포 스크립트를 함께 만들어두지 않으면 자동화가 "나만 쓸 수 있는 도구"에 머무른다는 걸 깨달았습니다. 실전 예제 — 엑셀 취합/가공 자동화, 파일 정리 자동화 실제로 자주 쓰는 패턴 몇 가지를 코드와 함께 공유합니다. 1) 여러 엑셀 파일을 하나로 취합하기. 특정 폴더 안의 엑셀 파일들을 전부 읽어서 하나의 데이터프레임으로 합치는 기본 패턴입니다. 파일별로 출처를 알 수 있도록 원본 파일명을 컬럼에 함께 기록해두는 게 나중에 문제를 추적할 때 큰 도움이 됩니다. python import pandas as pd import glob files = glob.glob("./reports/*.xlsx") df_list = [] for f in files: df = pd.read_excel(f, sheet_name="Sheet1") df["원본파일"] = f.split("/")[-1] df_list.append(df) merged = pd.concat(df_list, ignore_index=True) merged.to_excel("./merged_report.xlsx", index=False) 2) 날짜/공백 등 지저분한 값 정리하기. 사람이 직접 입력한 엑셀은 공백이나 형식 불일치가 흔합니다. 저는 취합 직후 반드시 아래와 같은 정제 단계를 거칩니다. python merged["담당자"] = merged["담당자"].astype(str).str.strip() merged["처리일자"] = pd.to_datetime(merged["처리일자"], errors="coerce") # 날짜 파싱 실패 건은 원본 파일명과 함께 별도 로그로 남긴다 error_rows = merged[merged["처리일자"].isna()] if not error_rows.empty: error_rows.to_excel("./date_parse_errors.xlsx", index=False) 3) 파일 정리 자동화 — 날짜/부서 기준으로 폴더 분류하기. 매일 쌓이는 원본 파일들을 날짜별 폴더로 자동 이동시키는 스크립트입니다. 원본 파일을 바로 옮기기보다, 항상 복사 후 검증하고 이동하는 방식으로 짜는 걸 원칙으로 삼고 있습니다. python import shutil, os from datetime import datetime src_dir = "./incoming" for filename in os.listdir(src_dir): if filename.endswith(".xlsx"): mtime = os.path.getmtime(os.path.join(src_dir, filename)) date_str = datetime.fromtimestamp(mtime).strftime("%Y%m%d") target_dir = os.path.join("./archive", date_str) os.makedirs(target_dir, exist_ok=True) shutil.move(os.path.join(src_dir, filename), os.path.join(target_dir, filename)) 여러 번 실수하며 얻은 자동화 스크립트 설계 노하우 몇 번의 사고를 겪고 나서 팀 내부적으로 정리한 원칙들을 공유합니다.
가장 중요한 원칙: 원본 파일은 절대 직접 수정하거나 덮어쓰지 않는다. 자동화 스크립트가 원본을 건드리다가 문제가 생기면 복구 자체가 불가능해집니다. 저는 항상 원본은 읽기 전용으로 취급하고, 결과물은 별도 파일로 저장하는 걸 절대 원칙으로 삼습니다.
모든 자동화 스크립트에 실행 로그를 남긴다. 언제, 어떤 파일을 몇 건 처리했는지, 오류가 있었는지를 별도 로그 파일에 남기지 않으면, 나중에 "왜 이 데이터가 이렇게 됐는지" 추적할 방법이 없습니다. 저는 logging 모듈로 실행 시각, 처리 건수, 예외 발생 여부를 항상 기록합니다. 예외 상황은 조용히 넘어가지 않고 반드시 표시한다. 초반에는 예외가 나면 그냥 try/except로 넘어가도록 짰는데, 이게 오히려 문제를 숨기는 결과를 낳았습니다. 특정 파일 처리에 실패했으면 그 사실을 로그와 별도 오류 리포트에 명확히 남겨서, 사람이 놓치지 않도록 하는 게 훨씬 중요하다는 걸 깨달았습니다. 작은 단위로 나눠서 재사용 가능하게 만든다. 처음엔 하나의 긴 스크립트에 모든 로직을 다 넣었는데, 나중에 비슷한 자동화 요청이 또 들어왔을 때 재사용이 거의 불가능했습니다. 이후로는 "파일 읽기", "정제", "저장", "알림"처럼 기능 단위로 함수를 쪼개두고, 새로운 요청이 오면 이 부품들을 조합하는 방식으로 작업 속도를 크게 줄였습니다. 처음엔 시간이 조금 더 걸리는 것 같아도, 몇 번째 요청부터는 이 구조 덕분에 개발 시간이 눈에 띄게 짧아졌습니다. 결과 공유는 사람이 확인하기 편한 형태로 한다. 아무리 정확하게 처리했어도, 결과를 보는 사람이 신뢰할 수 있는 형태로 전달하지 않으면 소용이 없었습니다. 처리 건수, 오류 건수, 처리 시각을 요약해서 메일이나 메신저로 함께 보내는 습관을 들이고 나서부터, 자동화 결과에 대한 주변의 신뢰도가 눈에 띄게 올라갔습니다. 실행 환경은 최대한 단순하게, 그리고 문서로 남긴다. 필요한 패키지 목록과 버전을 requirements.txt 형태로 정리해두고, 간단한 실행 방법을 README 형태로 남겨두는 것만으로도 나중에 다른 담당자에게 인수인계할 때의 부담이 크게 줄었습니다. 처음엔 귀찮아서 생략했던 부분인데, 결국 이 문서화 습관이 자동화 스크립트의 수명을 결정하는 요소였습니다.
정리하자면, 업무자동화 스크립트에서 진짜 어려운 부분은 판다스 문법이 아니라 "지저분한 현실 데이터를 어떻게 안전하게 다루고, 그 결과를 어떻게 신뢰받게 만드는가"였습니다. 코드는 생각보다 짧아도, 이 신뢰를 쌓는 과정이 훨씬 오래 걸렸습니다.
다음 글에서는 이 스크립트들을 매일 자동으로 실행되도록 스케줄링하고, 처리 결과를 메신저로 알림 받도록 만든 과정을 예제 코드와 함께 좀 더 구체적으로 다뤄보겠습니다.