중복 파일 삭제 스크립트를 돌렸다가 식은땀 흘린 날
"동료가 수정한 엑셀 파일에서 어떤 부분이 바뀌었는지 눈으로 찾고 있다", "어제 백업본과 오늘 파일을 비교해서 누가 어떤 값을 바꿨는지 확인해야 한다", "거래처가 보내온 새 견적서가 이전 견적서와 어떤 항목이 달라졌는지 확인해야 한다"…
이전 게시글 엑셀 자동 백업·버전 관리 편에서 버전별 백업을 만드는 방법을 소개했습니다. 이번 글에서는 한 단계 더 나아가, 백업해둔 이전 버전과 현재 파일을 비교해서 어떤 행이 추가되거나 삭제되거나 값이 바뀌었는지 자동으로 찾아내는 도구를 만들어 보겠습니다.
파이썬이 설치되어 있어야 합니다. 없다면 python.org에서 최신 버전을 받아 설치하세요. 설치 시 반드시 "Add Python to PATH"에 체크해야 합니다.
터미널(윈도우: CMD 또는 파워셸)을 열고 아래 명령어를 실행하세요:
pip install pandas openpyxl
pandas는 두 엑셀의 데이터를 비교하고 차이점을 찾는 모든 작업을 처리합니다. openpyxl은 비교 결과를 색상으로 강조한 엑셀 보고서로 저장하는 데 사용합니다.
💡 이 코드로 할 수 있는 것: 두 엑셀 파일을 기준 열(예: 거래처명, 주문번호)로 매칭해서 새로 추가된 행, 삭제된 행, 값이 변경된 셀을 모두 찾아내고, 변경 전후 값을 나란히 비교한 보고서를 색상으로 강조해 만듭니다.
비교할 두 파일은 같은 열 구조를 가지고 있어야 합니다. 각 행을 구분할 수 있는 고유 식별 열(거래처명, 주문번호 등)이 있어야 정확하게 비교됩니다.
[이전 파일] 거래처명 담당자 매출금액 납부상태
A주식회사 홍길동 5,200,000 완납
B기술연구소 김철수 980,000 미납
C물산 이영희 3,100,000 완납
[현재 파일] 거래처명 담당자 매출금액 납부상태
A주식회사 홍길동 5,200,000 완납
B기술연구소 김철수 1,200,000 완납 ← 금액·상태 변경됨
D상사 박민준 7,400,000 미납 ← 새로 추가됨
(C물산 행은 삭제됨)
아래 코드를 그대로 복사해서 메모장에 붙여넣고, compare_excel.py로 저장하세요. 저장 시 파일 형식은 "모든 파일", 인코딩은 UTF-8로 설정합니다.
import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import PatternFill, Font
from pathlib import Path
# ① 설정
OLD_PATH = r"C:\Users\내이름\Desktop\거래처현황_이전.xlsx" # ← 이전 버전 파일
NEW_PATH = r"C:\Users\내이름\Desktop\거래처현황_현재.xlsx" # ← 현재 버전 파일
OUTPUT_PATH = r"C:\Users\내이름\Desktop\비교결과.xlsx" # ← 결과 저장 경로
KEY_COLUMN = "거래처명" # ← 행을 구분하는 고유 식별 열
# ② 두 파일 읽기
old_df = pd.read_excel(OLD_PATH, engine="openpyxl")
new_df = pd.read_excel(NEW_PATH, engine="openpyxl")
print(f" ✔ 이전 파일: {len(old_df)}행 / 현재 파일: {len(new_df)}행")
old_df.set_index(KEY_COLUMN, inplace=True)
new_df.set_index(KEY_COLUMN, inplace=True)
old_keys = set(old_df.index)
new_keys = set(new_df.index)
# ③ 추가된 행 / 삭제된 행 찾기
added_keys = new_keys - old_keys
removed_keys = old_keys - new_keys
common_keys = old_keys & new_keys
added_rows = new_df.loc[list(added_keys)].reset_index() if added_keys else pd.DataFrame()
removed_rows = old_df.loc[list(removed_keys)].reset_index() if removed_keys else pd.DataFrame()
print(f" ✔ 추가된 행: {len(added_rows)}개")
print(f" ✔ 삭제된 행: {len(removed_rows)}개")
# ④ 공통 행에서 값이 변경된 셀 찾기
changed_rows = []
for key in common_keys:
old_row = old_df.loc[key]
new_row = new_df.loc[key]
for col in old_df.columns:
old_val = old_row[col]
new_val = new_row[col]
if pd.isna(old_val) and pd.isna(new_val):
continue
if str(old_val) != str(new_val):
changed_rows.append({
KEY_COLUMN: key,
"변경열": col,
"이전값": old_val,
"현재값": new_val,
})
df_changed = pd.DataFrame(changed_rows)
print(f" ✔ 값이 변경된 셀: {len(df_changed)}개")
# ⑤ 결과 엑셀 저장 (시트별로 분리)
with pd.ExcelWriter(OUTPUT_PATH, engine="openpyxl") as writer:
if not added_rows.empty:
added_rows.to_excel(writer, sheet_name="추가된행", index=False)
if not removed_rows.empty:
removed_rows.to_excel(writer, sheet_name="삭제된행", index=False)
if not df_changed.empty:
df_changed.to_excel(writer, sheet_name="변경된값", index=False)
# 시트가 하나도 없으면 "변화없음" 시트 생성
if added_rows.empty and removed_rows.empty and df_changed.empty:
pd.DataFrame([{"결과": "두 파일 사이에 변경사항이 없습니다."}]).to_excel(
writer, sheet_name="결과", index=False)
# ⑥ 시트별 색상 강조 적용
wb = load_workbook(OUTPUT_PATH)
green_fill = PatternFill(fill_type="solid", fgColor="D5F4E0") # 추가됨: 연한 초록
red_fill = PatternFill(fill_type="solid", fgColor="FADBD8") # 삭제됨: 연한 빨강
yellow_fill = PatternFill(fill_type="solid", fgColor="FCF3CF") # 변경됨: 연한 노랑
if "추가된행" in wb.sheetnames:
ws = wb["추가된행"]
for row in ws.iter_rows(min_row=2):
for cell in row:
cell.fill = green_fill
if "삭제된행" in wb.sheetnames:
ws = wb["삭제된행"]
for row in ws.iter_rows(min_row=2):
for cell in row:
cell.fill = red_fill
if "변경된값" in wb.sheetnames:
ws = wb["변경된값"]
for row in ws.iter_rows(min_row=2):
for cell in row:
cell.fill = yellow_fill
wb.save(OUTPUT_PATH)
print(f"\n✅ 완료! 비교 결과 저장 → {OUTPUT_PATH}")
OLD_PATH에 이전 버전 파일, NEW_PATH에 현재 버전 파일 경로를 입력합니다.KEY_COLUMN에 각 행을 구분할 수 있는 고유 열 이름을 입력합니다. 이 값이 중복되지 않아야 정확하게 비교됩니다.python compare_excel.py
정상 실행 시 터미널에 이렇게 출력됩니다:
✔ 이전 파일: 5행 / 현재 파일: 6행 ✔ 추가된 행: 1개 ✔ 삭제된 행: 1개 ✔ 값이 변경된 셀: 2개 ✅ 완료! 비교 결과 저장 → C:\Users\내이름\Desktop\비교결과.xlsx
결과 엑셀에는 추가된행(연한 초록), 삭제된행(연한 빨강), 변경된값(연한 노랑) 시트가 색상으로 구분되어 만들어집니다. 변경된값 시트에는 어느 거래처의 어떤 열이, 어떤 값에서 어떤 값으로 바뀌었는지 정확히 표시됩니다.
오류 1: KeyError 또는 비교가 부정확함
KEY_COLUMN에 중복된 값이 있으면 비교가 부정확해집니다. 예를 들어 같은 거래처명이 여러 행에 있다면 날짜 등을 조합한 별도의 고유 키를 만들어야 합니다:
old_df["고유키"] = old_df["거래처명"] + "_" + old_df["날짜"].astype(str) KEY_COLUMN = "고유키"
오류 2: 숫자 값인데 변경되지 않았는데 변경됨으로 표시됨
숫자가 한쪽은 정수(5200000), 다른 쪽은 텍스트("5,200,000")로 저장된 경우 다르다고 인식됩니다. 비교 전 숫자 형식을 통일하는 전처리를 추가하세요:
for col in ["매출금액"]:
old_df[col] = pd.to_numeric(old_df[col].astype(str).str.replace(",", ""), errors="coerce")
new_df[col] = pd.to_numeric(new_df[col].astype(str).str.replace(",", ""), errors="coerce")
오류 3: 빈 값(NaN)이 변경된 것으로 잘못 표시됨
코드에 이미 pd.isna()로 둘 다 빈 값인 경우는 건너뛰는 처리가 포함되어 있습니다. 한쪽만 빈 값인 경우는 정상적으로 변경 사항으로 표시됩니다.
중요한 파일이 변경될 때마다 알림을 받고 싶다면, 비교 결과 요약을 텔레그램으로 자동 발송할 수 있습니다.
from telegram_msg import send_message
if not (added_rows.empty and removed_rows.empty and df_changed.empty):
summary = (f"📊 엑셀 변경사항 감지\n\n"
f"➕ 추가: {len(added_rows)}건\n"
f"➖ 삭제: {len(removed_rows)}건\n"
f"✏️ 수정: {len(df_changed)}건")
send_message(summary)
💡 이전 게시글과 결합하면: 엑셀 자동 백업·버전 관리 편으로 매번 백업을 만들어두고, 이 코드로 직전 백업과 현재 파일을 비교하면 누가 무엇을 바꿨는지 항상 추적할 수 있습니다.
이 코드를 응용하면 변경 이력을 날짜별로 누적 기록하거나, 특정 열의 변경만 추적하는 것도 가능합니다.