엑셀 매크로(VBA) 보안 경고 끝! 파이썬으로 똑같은 작업 대체하기
"거래처 30곳에 보낼 신청서 PDF를 거래처명만 다르게 일일이 입력해야 한다", "정부 지원사업 신청서 양식이 PDF인데 같은 정보를 반복 입력해야 한다", "직원들의 휴가신청서를 매번 손으로 작성하고 있다"…
입력 가능한 PDF 양식(폼 필드가 있는 PDF)은 Adobe Acrobat에서 클릭해서 채우는 방식이 일반적이지만, 여러 개를 반복 작성해야 한다면 자동화가 훨씬 효율적입니다. 파이썬을 사용하면 PDF 양식의 입력란을 자동으로 채우고, 엑셀 목록을 기반으로 여러 개를 한꺼번에 생성할 수 있습니다.
파이썬이 설치되어 있어야 합니다. 없다면 python.org에서 최신 버전을 받아 설치하세요. 설치 시 반드시 "Add Python to PATH"에 체크해야 합니다.
PDF 양식 처리에 필요한 라이브러리를 설치합니다. 터미널(윈도우: CMD 또는 파워셸)을 열고 아래 명령어를 실행하세요:
pip install pypdf pandas openpyxl
pypdf는 PDF 안의 입력 가능한 폼 필드(텍스트 입력란, 체크박스 등)를 읽고 값을 채우는 기능을 지원합니다. pandas와 openpyxl은 엑셀 목록을 읽어 여러 신청서를 한꺼번에 생성하는 데 사용합니다.
⚠️ 중요한 전제조건: 이 방법은 PDF가 "입력 가능한 양식"(AcroForm)으로 만들어져 있을 때만 작동합니다. 그냥 스캔한 이미지 PDF나 텍스트만 있는 일반 PDF는 입력란이 없어 이 방법을 사용할 수 없습니다. PDF를 열었을 때 클릭하면 텍스트를 입력할 수 있는 칸이 있는지 먼저 확인하세요.
PDF 양식을 채우려면 먼저 각 입력란의 내부 이름(필드명)을 알아야 합니다. 아래 코드로 확인할 수 있습니다.
from pypdf import PdfReader
PDF_PATH = r"C:\Users\내이름\Desktop\신청서_양식.pdf" # ← 확인할 PDF 경로
reader = PdfReader(PDF_PATH)
fields = reader.get_fields()
if fields:
print(f" ✔ 발견된 입력란: {len(fields)}개\n")
for field_name, field_info in fields.items():
field_type = field_info.get("/FT", "알수없음")
print(f" 필드명: '{field_name}' (유형: {field_type})")
else:
print(" ⚠ 입력 가능한 필드가 없습니다. 이 PDF는 일반 PDF이거나 스캔본입니다.")
실행하면 PDF 안에 어떤 입력란이 있고 그 이름이 무엇인지 출력됩니다. 이 이름들을 다음 단계 코드에서 그대로 사용합니다.
아래 코드를 그대로 복사해서 메모장에 붙여넣고, fill_pdf.py로 저장하세요. 저장 시 파일 형식은 "모든 파일", 인코딩은 UTF-8로 설정합니다.
from pypdf import PdfReader, PdfWriter
from datetime import datetime
# ① 설정
TEMPLATE_PATH = r"C:\Users\내이름\Desktop\신청서_양식.pdf" # ← 원본 양식 PDF
OUTPUT_PATH = r"C:\Users\내이름\Desktop\신청서_작성완료.pdf" # ← 저장 경로
# ② 채울 내용 (2단계에서 확인한 필드명을 정확히 입력)
FIELD_VALUES = {
"신청인_이름": "홍길동",
"신청일자": datetime.now().strftime("%Y년 %m월 %d일"),
"연락처": "010-1234-5678",
"신청내용": "사무용품 구매 신청",
"금액": "150,000원",
}
# ③ PDF 읽기 및 양식 채우기
reader = PdfReader(TEMPLATE_PATH)
writer = PdfWriter()
writer.append(reader)
# 모든 페이지의 입력란에 값 채우기
for page in writer.pages:
writer.update_page_form_field_values(page, FIELD_VALUES)
print(f" ✔ {len(FIELD_VALUES)}개 필드 입력 완료")
# ④ 저장
with open(OUTPUT_PATH, "wb") as f:
writer.write(f)
print(f"\n✅ 완료! 작성된 PDF 저장 → {OUTPUT_PATH}")
거래처마다 다른 신청서를 한꺼번에 만드는 코드입니다. 아래 코드를 bulk_fill_pdf.py로 저장하세요.
from pypdf import PdfReader, PdfWriter
import pandas as pd
from pathlib import Path
# ① 설정
TEMPLATE_PATH = r"C:\Users\내이름\Desktop\신청서_양식.pdf"
EXCEL_PATH = r"C:\Users\내이름\Desktop\신청자목록.xlsx" # ← 신청자 정보 엑셀
OUTPUT_DIR = r"C:\Users\내이름\Desktop\신청서모음"
output_dir = Path(OUTPUT_DIR)
output_dir.mkdir(exist_ok=True)
# ② 엑셀 읽기 (열 이름은 PDF 필드명과 일치시키는 것을 권장)
df = pd.read_excel(EXCEL_PATH, engine="openpyxl")
print(f" ✔ 신청자 목록 로드: {len(df)}건")
# ③ 각 행마다 PDF 생성
success = 0
for _, row in df.iterrows():
field_values = {
"신청인_이름": str(row["이름"]),
"신청일자": str(row["신청일자"]),
"연락처": str(row["연락처"]),
"신청내용": str(row["신청내용"]),
"금액": f"{int(row['금액']):,}원",
}
reader = PdfReader(TEMPLATE_PATH)
writer = PdfWriter()
writer.append(reader)
for page in writer.pages:
writer.update_page_form_field_values(page, field_values)
out_path = output_dir / f"신청서_{row['이름']}.pdf"
with open(out_path, "wb") as f:
writer.write(f)
print(f" ✔ {out_path.name} 생성 완료")
success += 1
print(f"\n✅ 완료! 총 {success}개 신청서 생성 → {OUTPUT_DIR}")
fill_pdf.py의 FIELD_VALUES를 확인된 필드명에 맞게 수정 후 실행합니다.bulk_fill_pdf.py의 EXCEL_PATH를 설정하고 실행합니다.python fill_pdf.py
정상 실행 시 터미널에 이렇게 출력됩니다:
✔ 5개 필드 입력 완료 ✅ 완료! 작성된 PDF 저장 → C:\Users\내이름\Desktop\신청서_작성완료.pdf
오류 1: PDF를 열어도 입력한 값이 보이지 않음
일부 PDF 뷰어(특히 윈도우 기본 뷰어)는 값이 채워졌어도 화면에 즉시 반영하지 않는 경우가 있습니다. Adobe Acrobat Reader나 크롬 브라우저로 열어서 확인하세요.
오류 2: KeyError 또는 필드가 채워지지 않음
FIELD_VALUES의 키 이름이 2단계에서 확인한 실제 필드명과 정확히 일치하지 않는 경우입니다. 대소문자, 공백까지 정확히 일치해야 합니다. 2단계 코드를 다시 실행해서 정확한 이름을 복사하세요.
오류 3: 체크박스나 라디오 버튼이 채워지지 않음
체크박스는 텍스트가 아니라 "/Yes" 또는 "/On" 같은 특수 값으로 채워야 하는 경우가 많습니다. 2단계 코드의 출력에서 해당 필드의 유형이 /Btn으로 나온다면, 값으로 "/Yes"를 입력해보세요.
작성 완료된 신청서를 더 이상 수정할 수 없게 고정하려면 아래 코드를 저장 전에 추가합니다.
writer.set_need_appearances_writer(True)
# 모든 필드를 읽기 전용으로 설정
for page in writer.pages:
if "/Annots" in page:
for annot in page["/Annots"]:
annot_obj = annot.get_object()
annot_obj[NameObject("/Ff")] = NumberObject(1) # 읽기 전용 플래그
💡 이전 게시글과 결합하면: PDF 도장 자동 삽입 편과 결합하면 양식 작성 후 자동으로 도장까지 찍을 수 있고, 이메일 자동 발송 편과 결합하면 완성된 신청서를 자동으로 발송할 수 있습니다.
이 코드를 응용하면 체크박스·라디오버튼이 포함된 복잡한 양식도 처리하거나, 채운 PDF에 서명 이미지를 함께 삽입하는 것도 가능합니다.