
IT·디지털 자동화 블로그 · 파이썬 보고서 자동화
왜 PDF 자동화인가
PDF는 배포·보관에 유리하고, 인쇄 시 서식이 깨지지 않는다. 엑셀은 분석과 가공에 강점이 있지만, 공유 시 편집/수정 위험과 폰트 호환 이슈가 잦다. 파이썬 자동화로 엑셀 원본을 읽어 요약/시각화 후 표준 템플릿의 PDF를 생성하면, 보고 품질과 일정 준수율이 동시에 향상된다.
환경 준비
공통 패키지
pip install pandas openpyxl matplotlib
pandas는 엑셀 읽기/요약, matplotlib은 추이 차트 이미지를 생성하는 데 사용한다.
선택 도구
- ReportLab 설치:
pip install reportlab - Windows Excel COM: Microsoft Excel(데스크톱) +
pip install pywin32 - LibreOffice: 서버/리눅스에서
sofficeCLI
엑셀 읽기·요약·차트 이미지 준비
이 단계의 산출물은 이후 모든 방식(A/B/C)에서 공통으로 재사용한다.
# file: prep_data.py
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
# 1) 데이터 읽기
df = pd.read_excel("sales_data.xlsx") # 컬럼 예: 날짜, 지역, 매출, 비용
df["날짜"] = pd.to_datetime(df["날짜"])
# 2) 요약 테이블 (지역별 매출 합계)
summary = df.groupby("지역")["매출"].sum().reset_index().sort_values("매출", ascending=False)
# 3) 월별 매출 추이 차트 이미지
monthly = df.set_index("날짜").resample("M")["매출"].sum()
plt.figure()
monthly.plot(marker="o")
plt.title("월별 매출 추이")
plt.xlabel("월")
plt.ylabel("매출")
chart_path = f"chart_{datetime.now():%Y%m%d}.png"
plt.tight_layout()
plt.savefig(chart_path, dpi=150)
plt.close()
# 4) 중간 산출 저장
summary.to_csv("summary.csv", index=False)
print("요약 및 차트 준비 완료:", chart_path)
요약 CSV와 차트 PNG 파일을 생성해 두면, PDF 생성 단계에서 가볍게 끼워 넣을 수 있다.
방법 A: ReportLab으로 PDF 직접 생성(크로스플랫폼)
엑셀 서식을 그대로 쓰지는 않지만, 코드로 레이아웃과 스타일을 정밀 제어할 수 있다는 장점이 있다.
# file: make_pdf_reportlab.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image
from reportlab.lib.styles import getSampleStyleSheet
import pandas as pd
from datetime import datetime
styles = getSampleStyleSheet()
def build_pdf(summary_csv="summary.csv", chart_path=None, out_path=None, title="월간 실적 보고서"):
if out_path is None:
out_path = f"Report_{datetime.now():%Y%m%d}.pdf"
doc = SimpleDocTemplate(out_path, pagesize=A4)
story = []
story += [Paragraph(title, styles["Title"]), Spacer(1, 10)]
story += [Paragraph("지역별 매출 요약", styles["Heading2"]), Spacer(1, 6)]
df = pd.read_csv(summary_csv)
table_data = [["지역", "매출(합계)"]] + df.values.tolist()
tbl = Table(table_data, colWidths=[200, 200])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), colors.HexColor("#E2E8F0")),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CBD5E1")),
("ALIGN", (0,0), (-1,-1), "CENTER")
]))
story += [tbl, Spacer(1, 12)]
if chart_path:
story += [Paragraph("월별 매출 추이", styles["Heading2"]), Spacer(1, 6)]
story += [Image(chart_path, width=420, height=260), Spacer(1, 8)]
story += [Paragraph("코멘트: 상위 지역 판촉 강화, 하위 지역 원인 분석 및 개선 액션 제안.", styles["Normal"])]
doc.build(story)
print("PDF 생성 완료 →", out_path)
if __name__ == "__main__":
build_pdf(chart_path="chart_{}.png".format(datetime.now().strftime("%Y%m%d")))
서버·크론 환경에서 가장 안정적으로 돌릴 수 있다. 폰트/다국어가 필요하면 ReportLab의 TTF 임베딩을 추가하자.
방법 B: Excel(COM, Windows)로 PDF 내보내기(템플릿 유지)
기존 엑셀 서식·차트·인쇄 영역을 그대로 유지해 PDF를 만든다. Windows + 데스크톱 Excel 환경에서 강력하다.
# file: export_pdf_excel_com.py
# 필요: Microsoft Excel(데스크톱) 설치, pip install pywin32
import os
from datetime import datetime
import win32com.client as win32
def export_pdf(xlsx_path, sheet_name=None, out_dir="pdf_out"):
os.makedirs(out_dir, exist_ok=True)
excel = win32.gencache.EnsureDispatch("Excel.Application")
excel.Visible = False
wb = excel.Workbooks.Open(os.path.abspath(xlsx_path))
targets = [wb.Sheets(sheet_name)] if sheet_name else wb.Worksheets
for sht in targets:
out = os.path.join(out_dir, f"{sht.Name}_{datetime.now():%Y%m%d}.pdf")
# Type=0: PDF
sht.ExportAsFixedFormat(Type=0, Filename=out, Quality=0, IncludeDocProperties=True,
IgnorePrintAreas=False, OpenAfterPublish=False)
print("내보내기 완료 →", out)
wb.Close(SaveChanges=False)
excel.Quit()
if __name__ == "__main__":
export_pdf("보고서_템플릿.xlsx", sheet_name="대시보드")
팁: “페이지 레이아웃 → 인쇄영역 지정”과 “여백/머리말/바닥글”을 템플릿에서 미리 세팅하면 PDF 결과 품질이 일관된다.
방법 C: LibreOffice CLI로 일괄 PDF 변환(서버 친화)
Excel이 없는 리눅스/서버 환경에서 대량 변환에 적합하다. 서식 호환성이 100%는 아니므로 테스트가 필요하다.
# file: convert_with_soffice.py
# 사전 설치: LibreOffice (soffice)
import os, subprocess
from datetime import datetime
def convert_to_pdf(xlsx_path, out_dir="pdf_out"):
os.makedirs(out_dir, exist_ok=True)
cmd = [
"soffice", "--headless", "--convert-to", "pdf", "--outdir", out_dir, xlsx_path
]
subprocess.run(cmd, check=True)
base = os.path.splitext(os.path.basename(xlsx_path))[0]
out = os.path.join(out_dir, f"{base}.pdf")
# 날짜 스탬프 부여
stamped = os.path.join(out_dir, f"{base}_{datetime.now():%Y%m%d}.pdf")
if os.path.exists(out):
os.replace(out, stamped)
print("변환 완료 →", stamped)
if __name__ == "__main__":
convert_to_pdf("보고서_템플릿.xlsx")
헤드리스 모드로 무인 실행이 가능하다. 대량 변환 시 큐잉/로그/재시도 로직을 덧붙이면 운영 안정성이 올라간다.
자동 실행과 파일명 규칙
Windows 작업 스케줄러
- 작업 만들기 → 트리거: 매일 08:55
- 동작: 프로그램 시작 → python 경로 + 스크립트 지정
- 권한: 사용자가 로그온하지 않아도 실행
macOS·Linux 크론
# 매일 08:55 실행(요약→PDF)
55 8 * * * /usr/bin/python3 /path/prep_data.py && /usr/bin/python3 /path/make_pdf_reportlab.py
파일명에는 YYYYMMDD 스탬프를 부여해 버전 관리와 검색성을 확보하자. 예: Report_20251030.pdf
체크리스트
- 원본 엑셀 컬럼 타입과 날짜 파싱이 올바른가
- 요약 테이블과 차트 이미지가 정상 생성되는가
- PDF 방식(A/B/C) 중 환경에 맞는 경로를 선택했는가
- 로그/에러 처리/재시도 정책이 포함되어 있는가
- 스케줄러/크론에 안전하게 등록되어 있는가
자주 묻는 질문
폰트가 깨져 보일 때는?
ReportLab은 한글 TTF 임베딩을 설정한다. Excel/LibreOffice는 서버에 폰트를 설치하고 동일 폰트를 템플릿에서 지정한다.
대량 변환 시 느리면?
요약/차트 생성은 캐시 하고, PDF 변환만 병렬 처리한다. I/O 병목을 줄이고, 필요 없는 시트는 제외한다.
메일 발송까지 자동화하려면?
생성된 PDF 경로를 읽어 email.message.EmailMessage와 smtplib로 첨부 발송한다. 그룹별 템플릿 분기와 재시도/로그를 더하면 운영이 수월하다.
다음 글 예고: PDF 자동 발송과 수신자 그룹 템플릿
생성된 PDF를 부서/경영진 등 그룹별 제목·본문으로 자동 발송하고, 실패 재시도·로그·알림까지 갖춘 운영형 파이프라인을 만든다.
관련 읽을거리: 매일 자동 보고서 만들기 · 엑셀+이메일 자동 발송