파이썬으로 여러 엑셀 파일 하나로 합치기
월말 되면 지점별로, 혹은 월별로 엑셀 파일이 우르르 쌓이잖아요. 1월.xlsx, 2월.xlsx... 아니면 강남점, 분당점, 일산점... 이게 한두 개면 모르겠는데 12개, 많으면 50개씩 되면 얘기가 달라져요.
그걸 다 열어서 데이터 영역만 드래그하고, 복사하고, 통합 파일에 붙여넣고, 다음 파일 열고... 저도 예전엔 이거 하느라 야근 꽤 했거든요. 중간에 한 줄 빠뜨리기라도 하면 다시 처음부터.
이걸 파이썬으로 돌리면 클릭 몇 번이면 끝나요. 그런데 시작하기 전에 꼭 짚고 넘어가야 할 게 하나 있어요.
openpyxl에 merge 함수는 없습니다 (셀 병합과 헷갈리지 마세요)
검색하면 다들 "openpyxl merge"라고 치시는데요. 솔직히 말하면 파일을 합쳐주는 마법의 merge 함수 같은 건 없어요.
우리가 하는 "합치기"는 사실 별거 없거든요. 파일을 하나씩 열어서, 안에 있는 데이터를 읽고, 새 파일에 한 줄씩 옮겨 적는 거예요. 장부 12권을 펼쳐놓고 새 노트에 차례대로 베껴 적는 거랑 똑같아요.
그리고 한 가지 더. openpyxl에 merge_cells()라는 게 있긴 한데, 이건 엑셀에서 A1, B1 칸을 하나로 합치는 "셀 병합"이에요. 우리가 하려는 "파일 합치기"랑은 완전히 다른 기능이에요. 이름이 비슷해서 처음에 진짜 많이 헷갈리시더라고요.
이 글은 앞에서 배운 pathlib(폴더·경로 다루기, auto-02)이랑 openpyxl(엑셀 읽고 쓰기, auto-05)을 같이 써먹는 종합편이에요. 흐름은 딱 세 가지만 기억하시면 돼요. 목록 가져오기, 헤더 한 번만 쓰고 데이터만 쌓기, 출처 표시하기. 어렵지 않으니까 천천히 따라와 보세요.
1단계: 폴더 안 엑셀 목록 가져오기
먼저 합칠 파일들이 어디 있는지 파이썬한테 알려줘야겠죠. pathlib의 glob을 쓰면 폴더 안 엑셀 파일을 한 번에 긁어와요.
from pathlib import Path
folder = Path("매출") # 합칠 파일들이 든 폴더
files = sorted(folder.glob("*.xlsx")) # .xlsx만, 이름순으로 정렬
print(f"합칠 파일 {len(files)}개") # 몇 개 잡혔는지 먼저 확인
for f in files:
print(f.name) # 어떤 파일이 잡혔는지 출력
# 실행 결과:
# 합칠 파일 3개
# 2025_01.xlsx
# 2025_02.xlsx
# 2025_03.xlsx
sorted로 감싸준 거 보이시죠? 이거 안 하면 1월, 10월, 2월 이런 식으로 순서가 엉킬 수 있어서 넣어줬어요.
2단계: 통합 워크북 만들고 헤더는 딱 한 번만
이제 데이터를 옮겨 담을 새 엑셀(통합 파일)을 만들 차례예요. 여기서 핵심은 제목 줄(헤더)을 한 번만 쓰는 것이에요.
from openpyxl import Workbook
merged_wb = Workbook() # 새 통합 워크북 만들기
merged_ws = merged_wb.active # 기본 시트 선택
merged_ws.title = "통합" # 시트 이름 바꾸기
merged_ws.append(["이름", "부서", "매출", "출처파일"]) # 헤더를 딱 한 번만
왜 한 번만 쓰냐면요. 파일마다 맨 윗줄에 "이름 / 부서 / 매출"이 들어있잖아요. 그걸 그냥 다 합치면 데이터 중간중간에 "이름 부서 매출" 글자가 12번씩 끼어들어요. 손으로 복붙할 때도 제목 줄은 빼고 알맹이만 붙여넣으시잖아요. 똑같은 원리예요.
3단계: 각 파일에서 데이터만 읽어서 쌓기
이제 파일을 하나씩 열어서, 제목 줄은 건너뛰고 데이터만 가져올 거예요.
from openpyxl import load_workbook
wb = load_workbook(file) # file은 Path 객체
ws = wb.active
for row in ws.iter_rows(min_row=2, values_only=True): # 2행부터 = 헤더 건너뜀
if not any(row): # 한 줄이 전부 비어있으면 건너뜀
continue
merged_ws.append(list(row) + [file.stem]) # 데이터 끝에 출처 붙여서 추가
min_row=2가 핵심이에요. 1행(제목)은 건드리지 말고 2행부터 읽으라는 뜻이거든요. values_only=True는 셀 객체 말고 값만 깔끔하게 달라는 거고요.
어느 파일에서 왔는지 표시하기 (출처 컬럼)
위 코드에서 file.stem 부분, 이게 은근 실무에서 효자예요.
데이터를 다 합치고 나면 "어, 이 줄이 1월 거였나 3월 거였나?" 헷갈리거든요. 그래서 각 줄 끝에 출처를 같이 적어두는 거예요.
file.name은"2025_01.xlsx"(확장자까지)file.stem은"2025_01"(확장자 뺀 이름)
보기엔 stem이 훨씬 깔끔해서 이걸 많이 써요.
다 합쳐서 한 번에 돌리는 스크립트
지금까지 조각조각 본 걸 하나로 합치면 이렇게 돼요. 이게 이 글의 핵심이에요.
from pathlib import Path
from openpyxl import Workbook, load_workbook
input_folder = Path("매출") # 입력 폴더
output_file = Path("결과") / "통합.xlsx" # 출력은 다른 폴더로 (이유는 아래에)
output_file.parent.mkdir(exist_ok=True) # 결과 폴더 없으면 만들기
merged_wb = Workbook()
merged_ws = merged_wb.active
merged_ws.title = "통합"
merged_ws.append(["이름", "부서", "매출", "출처파일"]) # 헤더 한 번만
files = sorted(input_folder.glob("*.xlsx"))
for file in files:
if file.name.startswith("~$"): # 엑셀 열어둘 때 생기는 임시파일 제외
continue
wb = load_workbook(file)
ws = wb.active
for row in ws.iter_rows(min_row=2, values_only=True):
if not any(row):
continue
merged_ws.append(list(row) + [file.stem]) # 출처 컬럼 추가
print(f"{file.name} 합치는 중...")
merged_wb.save(output_file)
print(f"완료! {output_file} 저장됨")
# 실행 결과:
# 2025_01.xlsx 합치는 중...
# 2025_02.xlsx 합치는 중...
# 2025_03.xlsx 합치는 중...
# 완료! 결과\통합.xlsx 저장됨
이 방식은 모든 파일이 같은 양식(열 순서가 같음)이라는 전제예요. A파일은 이름-부서-매출인데 B파일은 부서-이름-매출이면 데이터가 엉켜요. 보통 같은 템플릿으로 받으니까 대부분 괜찮을 거예요.
줄이 자꾸 두 배씩 늘어나요 (제가 한참 헤맨 부분)
여기, 제가 처음에 진짜 한참 헤맨 부분이라 꼭 말씀드릴게요.
통합 파일을 합칠 파일들이랑 같은 폴더에 저장하면 무슨 일이 벌어지냐면요. glob("*.xlsx")가 통합.xlsx까지 목록에 끌어와요. 그러면 다시 돌릴 때마다 이전 결과가 또 합쳐져서, 줄 수가 30줄 → 60줄 → 120줄... 이렇게 눈덩이처럼 불어나요.
저는 이걸 모르고 "왜 자꾸 데이터가 두 배가 되지?" 하면서 한참 멍하니 봤거든요.
그래서 위 코드에서 출력 파일을 결과 폴더로 따로 뺀 거예요. 입력 폴더랑 출력 폴더를 처음부터 분리해두면 이 사고가 안 나요.
자주 만나는 에러
PermissionError: [Errno 13] Permission denied: '통합.xlsx'
저장이 안 되고 이 에러가 뜨면, 십중팔구 그 통합 파일을 엑셀로 열어둔 상태예요. 윈도우에서 진짜 흔해요. 엑셀 창 닫고 다시 돌리면 됩니다.
합쳤는데 헤더만 있고 데이터가 없어요
glob에 파일이 하나도 안 잡힌 경우예요. 폴더 경로 오타거나, 파일이 .xlsx가 아니라 구형 .xls일 수 있어요. openpyxl은 .xls를 못 읽거든요. 엑셀에서 .xlsx로 다시 저장하면 돼요. 그래서 아까 len(files)로 몇 개 잡혔는지 먼저 찍어보는 습관이 좋아요.
직접 해보기
- 폴더 하나 만들고 같은 양식 엑셀 2~3개 넣어보세요. 손으로 대충 만드셔도 돼요.
- 위 메인 스크립트를 돌려서 통합.xlsx를 만들어보세요.
- 출처파일 컬럼이 잘 들어갔는지 확인해보세요.
- 보너스: 한 번 더 돌려보고 줄 수가 안 늘어나는지 확인해보세요. (입출력 폴더 분리 효과를 직접 느낄 수 있어요.)
힌트: 데이터가 안 보이면 print(len(files))로 파일이 몇 개 잡혔는지부터 확인해보세요. 0이면 경로 문제예요.
지금은 데이터를 그냥 모으기만 했는데, 이걸 상사한테 그대로 보내기엔 좀 밋밋하잖아요. 다음 글에서는 합친 데이터에 제목 굵게, 색 입히고, 합계 행에 막대 차트까지 넣어서 "보고서답게" 만드는 법을 해볼 거예요.
제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀
'Application > Python' 카테고리의 다른 글
| [Python] 08. 파이썬으로 구글 시트 자동 연동하기 (gspread) (0) | 2026.06.29 |
|---|---|
| [Python] 07. 파이썬으로 엑셀 자동 보고서 만들기 (서식과 차트) (0) | 2026.06.17 |
| [Python] 05. 파이썬 엑셀 자동화, openpyxl로 시작하기 (0) | 2026.06.15 |
| [Python] 04. 파이썬으로 폴더별 파일 자동 분류하기 (확장자별 정리) (0) | 2026.06.12 |
| [Python] 03. 파이썬으로 파일 이름 일괄 변경 자동화하기 (0) | 2026.06.11 |