파이썬으로 Word 문서 자동 생성하기 (python-docx)
이름이랑 날짜만 바꾼 똑같은 공문을 30번 새로 타이핑해 본 적 있으세요? 양식은 그대로인데 말이죠. 안내문, 확인서, 참석 요청 공문... 이런 걸 사람 수만큼 하나하나 찍어내는 일, 은근히 야근의 주범이잖아요.
지난 글까지가 PDF에서 내용을 꺼내는(읽는) 쪽이었다면, 이번엔 방향이 정반대예요. 이제 우리가 문서를 만들어내는(쓰는) 쪽으로 넘어갑니다. 그것도 파이썬이 대신 30장을 순식간에 찍어내게요.
이게 엑셀/문서 파트의 마지막 글이에요. 여기까지 오시느라 고생 많으셨어요.
그런데 설치가 좀 특이해요 (python-docx)
시작하기 전에 이거 하나만 먼저 못박고 갈게요. 안 그러면 첫 줄부터 막히시거든요.
pip install python-docx
깔 때는 이렇게 python-docx라고 치는데, 정작 코드에서 불러올 때는:
from docx import Document # 부를 땐 docx! (python_docx 아니에요)
깔 때는 python-docx, 부를 때는 docx. 이름이 서로 달라요.
이게 이 글에서 제일 많이 만나실 함정이에요. import python_docx라고 쓰면 바로 ModuleNotFoundError가 뜨거든요. 지난 엑셀 글(openpyxl)은 깔 때랑 부를 때 이름이 같아서 이런 게 없었는데, 이번엔 달라요. 미리 기억해 두세요.
빈 문서에 제목·문단 쌓기 (Document, add_paragraph)
여기서 좀 안심하셔도 돼요. 만드는 절차가 엑셀 때랑 판박이거든요. 그때 Workbook() 만들고 내용 넣고 wb.save() 했잖아요. 워드도 똑같아요.
from docx import Document
doc = Document() # 빈 새 문서 (워드 새 창 켜는 느낌)
doc.add_heading("업무 보고서", level=0) # 문서 제목 (level=0이 가장 큼)
doc.add_heading("1. 개요", level=1) # 대제목
doc.add_paragraph("이번 주 진행 상황을 정리했습니다.") # 일반 문단
doc.save("보고서.docx") # 저장 (엑셀 wb.save와 같은 감각!)
print("보고서.docx 생성 완료")
# 실행 결과:
# 보고서.docx 생성 완료
add_heading은 제목 줄 치기, add_paragraph는 문단 타이핑, doc.save는 Ctrl+S. 워드로 손수 하던 동작을 코드가 그대로 대신하는 거예요. level 숫자가 커질수록 하위 제목이 되고요.
참, doc.save() 안 하면 파일이 안 생겨요. 엑셀 때 append만 하고 save 빼먹으면 파일 안 바뀌던 거, 그거랑 똑같은 습관이에요.
글자를 굵게·크게 — run이 뭔가요
여기가 살짝 첫 벽이에요. 굵게나 크기 같은 서식은 문단이 아니라 run(런) 이라는 데다 걸거든요.
run이 뭐냐면, 워드에서 글 쓰다가 중간 몇 글자만 드래그해서 굵게 만들잖아요? 그러면 그 문단이 "보통 글자 덩어리 + 굵은 글자 덩어리"로 나뉘죠. 이 같은 서식으로 이어진 글자 덩어리 하나하나가 run이에요.
from docx import Document
from docx.shared import Pt # 글자 크기(포인트)용
from docx.enum.text import WD_ALIGN_PARAGRAPH # 정렬용
doc = Document()
title = doc.add_paragraph() # 빈 문단 하나
run = title.add_run("월간 실적 요약") # 그 안에 글자 조각(run) 추가
run.bold = True # 이 조각만 굵게
run.font.size = Pt(20) # 20포인트로
title.alignment = WD_ALIGN_PARAGRAPH.CENTER # 정렬은 '문단'에 건다!
doc.save("실적요약.docx")
여기서 딱 하나만 기억하세요.
글자 모양(굵기·크기·색)은 run에, 줄 배치(왼쪽·가운데·오른쪽)는 문단에.
이게 헷갈려서 p.bold나 run.alignment 찾다가 많이들 막히시더라고요. Pt나 WD_ALIGN_PARAGRAPH 같은 건 그냥 위처럼 import 한 줄 복사해 쓰시면 돼요. 외울 필요 없어요.
표와 이미지 넣기
이런 것도 된다는 정도로 가볍게 보고 갈게요. 표는 이렇게요.
from docx import Document
doc = Document()
table = doc.add_table(rows=1, cols=3) # 머리글용 1행만 먼저
table.style = "Table Grid" # 테두리 있는 표 (없으면 선이 안 생겨요)
table.cell(0, 0).text = "이름" # 셀은 (행, 열), 둘 다 0부터!
table.cell(0, 1).text = "부서"
table.cell(0, 2).text = "직급"
members = [("김영희", "개발팀", "대리"), ("박철수", "영업팀", "과장")]
for name, dept, rank in members:
row = table.add_row() # 새 행 추가
row.cells[0].text = name
row.cells[1].text = dept
row.cells[2].text = rank
doc.save("명단.docx")
cell(행, 열)도 0부터예요. cell(1, 1)이 1행 1열이 아니라 2행 2열이에요. 파이썬은 첫 번째가 0, 또 나왔죠. PDF 페이지 셀 때도 그랬잖아요.
이미지는 doc.add_picture("로고.png", width=Inches(2)) 이렇게 넣고, 페이지를 끊고 싶으면 doc.add_page_break()를 쓰면 돼요. 이미지는 파일명만 쓰면 코드 실행하는 폴더 기준이니 경로만 조심하시고요.
여기가 핵심 — 양식에 데이터 채우기
자, 앞은 워밍업이었어요. 실무에서 진짜 쓰는 건 지금부터예요. 이게 이 글의 90%예요.
빈 문서를 코드로 하나하나 쌓는 게 아니라, 워드로 예쁘게 만들어 둔 양식을 열어서 바뀌는 곳만 갈아끼우는 방식이에요. 관공서 신청서에 성명·날짜 빈칸만 채워 넣는 거랑 똑같아요.
먼저 워드로 공문 양식을 만드시고, 바뀌는 자리에 이렇게 적어서 양식.docx로 저장해 두세요.
수신: {name} 귀하
발신일: {date}
{name}님, {body}
이 {name}, {date} 같은 게 자리표시자(빈칸)예요. 이제 파이썬이 이 빈칸을 실제 값으로 바꿔치기합니다.
from docx import Document
doc = Document("양식.docx") # 새로 만드는 게 아니라 '기존 양식'을 연다! (괄호 안 파일명)
data = {
"{name}": "김영희",
"{date}": "2025년 10월 9일",
"{body}": "다음 주 정기 교육에 참석 바랍니다.",
}
for p in doc.paragraphs: # 문서의 모든 문단을 돌며
for key, value in data.items(): # 바꿀 항목마다
if key in p.text: # 이 문단에 자리표시자가 있으면
for run in p.runs: # 문단 속 글자 조각(run)들을
run.text = run.text.replace(key, value) # 실제 값으로 바꾼다
doc.save("공문_김영희.docx") # 다른 이름으로! (원본 양식은 보존)
print("공문 생성 완료")
흐름은 딱 세 단계예요. 양식 열기 → 자리표시자를 실제 값으로 replace → 다른 이름으로 저장.
Document()는 빈 새 문서지만, Document("양식.docx")처럼 괄호에 파일명을 넣으면 기존 파일을 여는 거예요. 이 괄호 하나 차이가 커요. 그리고 아까 배운 run이 여기서 실전으로 쓰여요. 문단 텍스트를 통째로 바꾸면 서식이 다 날아갈 수 있어서, 서식을 지키려고 run 단위로 replace 하는 거거든요.
명단으로 개인별 공문 한 번에 (일괄 생성)
그리고 이걸 반복문에 넣으면... 명단 30명이면 공문 30장이 순식간이에요. 이 글의 진짜 감동 포인트예요.
from docx import Document
# 명단 (실무에선 지난 openpyxl 글처럼 엑셀에서 읽어와도 돼요)
people = [
{"name": "김영희", "date": "2025-10-09", "body": "10월 교육에 참석 바랍니다."},
{"name": "박철수", "date": "2025-10-09", "body": "10월 교육에 참석 바랍니다."},
{"name": "이민지", "date": "2025-10-09", "body": "10월 교육에 참석 바랍니다."},
]
for person in people: # 한 사람씩
doc = Document("양식.docx") # 매번 '깨끗한 양식'을 새로 연다 (중요!)
for p in doc.paragraphs:
for key in ["name", "date", "body"]:
holder = "{" + key + "}" # {name} 형태의 자리표시자
if holder in p.text:
for run in p.runs:
run.text = run.text.replace(holder, person[key])
doc.save(f"공문_{person['name']}.docx") # 사람 이름으로 파일 저장
print(f"공문_{person['name']}.docx 생성 완료")
print("전체 공문 생성 끝!")
# 실행 결과:
# 공문_김영희.docx 생성 완료
# 공문_박철수.docx 생성 완료
# 공문_이민지.docx 생성 완료
# 전체 공문 생성 끝!
여기서 두 가지 습관만 꼭 챙기세요.
하나, 반복문 안에서 매번 Document("양식.docx")를 새로 열어요. 밖에서 한 번만 열어 재사용하면 앞사람 값이 남아서 다 뒤섞여요. 사람마다 깨끗한 양식지를 한 장씩 새로 꺼내는 감각이에요.
둘, f"공문_{person['name']}.docx"처럼 파일명에 이름을 넣어요. 안 그러면 서로 같은 파일에 덮어써서 마지막 한 명만 남거든요. f-string, 파일명 일괄 변경 배울 때 써봤던 그거예요.
자주 만나는 에러
가장 많이 만나실 건 역시 이거예요.
ModuleNotFoundError: No module named 'python_docx'
import python_docx라고 쓰셨을 거예요. 깔 때는 python-docx, 부를 때는 docx. from docx import Document로 고치면 돼요. 아니면 아예 설치를 안 하셨을 수도 있는데, 그땐 pip install python-docx 먼저요.
두 번째로, 코드는 분명 맞는데 {name}이 그대로 안 바뀌는 경우가 있어요. 당황스러우시겠지만 코드 탓이 아닐 수 있어요. 워드가 자리표시자를 여러 조각으로 쪼개 저장해서 그런 건데요, 양식에서 그 부분을 지우고 커서 안 옮기고 한 번에 다시 타이핑해서 저장해 보세요. 대부분 해결돼요.
그리고 PermissionError가 뜨면 그 워드 파일을 지금 열어둔 거예요. 창 닫고 다시 실행하시면 됩니다.
오늘 해보시면 좋은 것
- 본인 업무에서 자주 쓰는 양식(공문·안내문·확인서 등)을 워드로 하나 만들고, 바뀌는 부분에
{name},{date}넣어서양식.docx로 저장해 보세요. - 위 템플릿 예제로 한 명분을 채워서, 결과 문서를 열어 자리표시자가 실제 값으로 바뀌고 서식이 유지됐는지 확인해 보세요.
- 명단 3~5명으로 일괄 생성까지 돌려서 파일이 이름별로 잘 저장되나 보세요. (힌트: 반복문 안에서 매번 양식을 새로 여는 것, 이거 하나만 놓치지 마세요.)
여기까지 오셨으면 이제 엑셀도 읽고 쓰고 합치고, PDF도 나누고 뽑고, Word 문서까지 자동으로 찍어낼 수 있게 됐어요. 손으로 옮겨 치던 문서 작업 상당수를 파이썬이 대신하는 거죠. 문서 파트는 여기서 한 단락 마무리예요. 정말 고생하셨어요.
그런데 공문 30장을 만들어 놓고 나면 바로 이런 생각이 들잖아요. '이걸 또 일일이 첨부해서 30명한테 메일 보내야 하나...' 다음 글부터는 파이썬으로 이메일을 자동 발송하는 법으로 넘어가요. 오늘 만든 '양식 채워 일괄 생성'이랑 그게 만나면, 명단만 넣으면 개인별 문서를 만들어 각자에게 메일까지 쏘는 시스템이 되거든요. 그건 조금 뒤에 합쳐볼게요.
제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀
'Application > Python' 카테고리의 다른 글
| [Python] 11. 파이썬으로 PDF 텍스트 추출하고 엑셀로 정리하기 (0) | 2026.07.03 |
|---|---|
| [Python] 10. 파이썬으로 PDF 합치고 나누기 (PyPDF2) (0) | 2026.07.02 |
| [Python] 09. 파이썬 미니 프로젝트: 월별 매출 정리 자동화 (1) | 2026.07.01 |
| [Python] 08. 파이썬으로 구글 시트 자동 연동하기 (gspread) (0) | 2026.06.29 |
| [Python] 07. 파이썬으로 엑셀 자동 보고서 만들기 (서식과 차트) (0) | 2026.06.17 |