처음 시도한 업무 자동화, 3번 실패하고서야 깨달은 것들
처음 시도한 업무 자동화, 3번 실패하고서야 깨달은 것들
이 블로그에는 "완성 코드"만 올라오지만, 사실 모든 자동화가 처음부터 깔끔하게 완성되지는 않습니다. 이번 글에서는 실제로 겪었던 시행착오 하나를 그대로 풀어보려 합니다. 지금까지 소개한 완성 코드들이 왜 지금의 형태가 되었는지, 그 뒤에 있는 실패 과정을 공유하면 자동화를 처음 시도하는 분들께 더 도움이 될 것 같았습니다.
상황은 이랬습니다. 거래처별로 흩어진 엑셀 파일 수십 개를 매달 하나로 합쳐서 정리하는 작업을, 파이썬으로 자동화하기로 마음먹었습니다.
시도 1 — "일단 되겠지" 하고 짠 코드, 반나절 만에 무너짐
처음에는 이렇게 단순하게 접근했습니다.
import pandas as pd
from pathlib import Path
all_data = []
for file in Path("거래처파일").glob("*.xlsx"):
df = pd.read_excel(file)
all_data.append(df)
result = pd.concat(all_data)
result.to_excel("합친결과.xlsx")
파일 5개로 테스트했을 때는 잘 됐습니다. 문제는 실제 폴더에 파일 40개를 넣고 돌렸을 때 터졌습니다.
무엇이 잘못됐나: 거래처마다 엑셀 헤더 이름이 조금씩 달랐습니다. 어떤 파일은 "거래처명", 어떤 파일은 "업체명"이었고, 어떤 파일은 1행이 아니라 2행부터 데이터가 시작했습니다. pd.concat()은 이걸 그대로 합쳐버려서 결과 파일이 열 수십 개가 뒤죽박죽 섞인 형태로 나왔습니다. "일단 합치고 보자"는 접근이 실무 데이터의 비일관성 앞에서 완전히 무너진 순간이었습니다.
❌ 실패 원인: 테스트를 5개짜리 "깨끗한" 샘플로만 하고, 실제 40개 파일의 다양성을 확인하지 않았습니다.
시도 2 — 헤더는 맞췄는데, 이번엔 한글이 깨짐
헤더 이름을 통일하는 매핑 딕셔너리를 추가했습니다.
COLUMN_MAP = {"업체명": "거래처명", "회사명": "거래처명"}
all_data = []
for file in Path("거래처파일").glob("*.xlsx"):
df = pd.read_excel(file)
df = df.rename(columns=COLUMN_MAP)
all_data.append(df)
result = pd.concat(all_data, ignore_index=True)
result.to_excel("합친결과.xlsx", index=False)
이번엔 대부분 잘 합쳐졌습니다. 그런데 결과 파일을 열어보니 일부 행의 거래처명이 물음표나 네모(□)로 깨져 있었습니다.
무엇이 잘못됐나: 나중에 알고 보니, 오래된 회계 프로그램에서 내보낸 몇몇 파일이 CSV를 .xlsx로 확장자만 바꾼 파일이었고, 인코딩이 EUC-KR이었습니다. pd.read_excel()은 진짜 엑셀 바이너리 형식을 기대하는데, 이 파일들은 사실 텍스트 파일이라 읽는 방식 자체가 틀렸던 것입니다.
❌ 실패 원인: "확장자가 .xlsx면 당연히 진짜 엑셀 파일"이라고 가정했습니다. 파일 형식은 확장자가 아니라 내용으로 확인해야 한다는 것을 이때 배웠습니다.
시도 3 — 파일 형식은 해결, 그런데 매달 반복하려니 또 문제
파일 형식을 자동으로 구분해서 처리하도록 개선했습니다.
import pandas as pd
import chardet
from pathlib import Path
def read_any_file(file):
try:
return pd.read_excel(file) # 먼저 진짜 엑셀로 시도
except Exception:
with open(file, "rb") as f:
enc = chardet.detect(f.read(10000))["encoding"] or "cp949"
return pd.read_csv(file, encoding=enc) # 실패하면 CSV로 재시도
all_data = []
for file in Path("거래처파일").glob("*.xlsx"):
df = read_any_file(file)
df = df.rename(columns=COLUMN_MAP)
all_data.append(df)
result = pd.concat(all_data, ignore_index=True)
result.to_excel("합친결과.xlsx", index=False)
이제 파일 형식 문제는 해결됐습니다. 그런데 다음 달에 똑같은 스크립트를 다시 돌렸더니, 이번엔 중복 데이터가 생겼습니다. 지난달 파일을 폴더에서 안 지우고 그냥 뒀더니, 지난달 데이터와 이번 달 데이터가 둘 다 합쳐진 것입니다.
❌ 실패 원인: "한 번 실행하고 끝"이 아니라 "매달 반복 실행"한다는 것을 코드 설계 단계에서 고려하지 않았습니다.
결국 이렇게 정리됐습니다 — 3번의 실패에서 나온 최종 원칙
세 번의 실패를 거치고서야, 지금 이 블로그의 완성 코드들에 공통적으로 들어가는 원칙들이 자연스럽게 만들어졌습니다.
1. 헤더 이름은 반드시 매핑 딕셔너리로 통일한다 → CSV 자동 병합 편의 열 이름 통일 로직이 여기서 나왔습니다. 2. 파일 형식은 확장자가 아니라 실제 내용으로 판단한다 → 인코딩 자동 감지 편이 이 문제를 별도로 다루게 된 계기입니다. 3. 반복 실행을 전제로 설계한다 (중복 방지, 날짜 접두어, 로그 기록) → 엑셀 버전 관리 편의 타임스탬프 백업 방식이 이 교훈에서 나왔습니다. 4. "정상적으로 처리된 파일 수 / 실패한 파일 수"를 항상 출력한다 → 지금까지 소개한 거의 모든 완성 코드에 "✔ 성공 / ✘ 실패" 로그가 빠짐없이 들어가는 이유입니다.
돌아보며 — 이 시행착오가 알려준 것
완성된 코드만 보면 "처음부터 저렇게 짰겠지"라고 생각하기 쉽지만, 실제로는 실무 데이터의 예외 상황을 하나씩 마주치면서 코드가 점점 튼튼해지는 과정이었습니다. 특히 아래 세 가지는 자동화를 처음 시도하는 분들께 꼭 전하고 싶은 부분입니다.
첫째, 테스트는 반드시 "지저분한" 실제 데이터로 하세요. 깨끗하게 정리된 샘플 파일 5개로 테스트하면 코드가 작동하는 것처럼 보이지만, 실무 데이터의 예외 상황(다른 헤더명, 다른 형식, 빈 값)은 다릅니다.
둘째, "한 번 실행"이 아니라 "여러 번 실행"을 가정하고 설계하세요. 자동화 스크립트는 보통 반복 실행됩니다. 처음 실행할 때만 맞는 코드는 두 번째 실행에서 예상치 못한 문제를 일으킵니다.
셋째, 실패했을 때 무엇이 잘못됐는지 바로 알 수 있게 로그를 남기세요. 이 블로그의 모든 코드에 있는 ✔, ✘ 출력이 괜히 있는 게 아닙니다. 조용히 실패하는 코드가 가장 위험합니다.
💡 지금 비슷한 상황이라면: 위에서 언급한 CSV 자동 병합 편은 이 시행착오를 모두 반영해서 처음부터 완성된 형태로 정리해둔 글입니다. 같은 실패를 반복하지 않도록 참고하시면 좋겠습니다.
핵심 요약
- 실패 1: 깨끗한 샘플로만 테스트 → 실무 데이터의 헤더 불일치로 무너짐
- 실패 2: 확장자만 믿고 파일 형식 가정 → 인코딩 문제로 한글 깨짐
- 실패 3: 한 번 실행만 고려 → 반복 실행 시 중복 데이터 발생
- 얻은 원칙: 헤더 매핑, 내용 기반 형식 판단, 반복 실행 대비, 성공/실패 로그 기록
