AI 해결 노트 · 2026-09-18 · 실측 2026-09-18
PDF 표를 엑셀로 옮기기 — 파일을 어디에도 올리지 않고, 스캔본이 안 되는 이유까지
한 줄로
PDF 안의 표를 엑셀로 옮기는 일은 온라인 변환 사이트에 올리지 않아도 됩니다. 엑셀에 이미 들어 있는 「데이터 가져오기 > PDF에서」, 워드로 PDF 열기, 둘 다 안 될 때 파이썬(pdfplumber) 순서로 해 보시면 됩니다. 저희가 만든 시험 표에서는 세 방법 모두 금액이 글자로 들어와 엑셀 SUM이 0이 나왔습니다. 스캔본(사진으로 된 PDF)에서는 둘이 아무것도 못 가져왔고, 워드만 표를 만들어 냈는데 그 숫자가 틀렸습니다.
이런 분께
- 거래처가 PDF로만 준 내역서를 엑셀에 옮겨야 하는데, 회사 자료라 변환 사이트에 올리기가 꺼려지는 분
- 옮기긴 옮겼는데 합계가 안 잡히거나 원본과 금액이 안 맞는 분
- 스캔해서 받은 PDF가 왜 안 되는지 설명해야 하는 분
실측 환경
| 항목 | 값 |
|---|---|
| OS | Windows 11 Home (10.0.26200) |
| 셸 | Git Bash |
| Excel | 16.0 (Build 20326.0) |
| Word | 16.0 (Build 16.0.20326) |
| Python | 3.12.10 |
| 파이썬 꾸러미 | pdfplumber 0.11.10, PyMuPDF 1.28.0, openpyxl 3.1.5 |
| 시험 파일 | 시험용으로 지어낸 표. 회사 자료와 사람 이름은 넣지 않았습니다 |
시험에 쓴 표
엑셀로 표를 하나 만들어 PDF로 내보냈습니다. 시트로는 23행이고, 맨 위 제목 줄을 빼면 표 자체는 22행입니다. 머리글 1행, 데이터 20행, 합계 1행입니다. 실제 업무 표에서 자주 말썽을 부리는 것들을 일부러 넣었습니다.
- 부서 열은 같은 부서끼리 세로로 병합(
B3:B7,B8:B13,B14:B18,B19:B22) - 품목 한 칸에 줄바꿈(
A4 복사용지\n(80g, 2500매)) - 수량·단가·금액 열의 표시 형식은 `#,##0`, 곧 천 단위 쉼표
- 합계 행은 A~C를 가로로 병합(
A23:C23) - 머리글부터 합계까지 132칸 중 130칸에 실선 테두리
옮긴 결과가 맞는지 볼 기준은 셋으로 정했습니다. 데이터 20행 / 수량 합 251 / 금액 합 6,093,800.

같은 표로 PDF를 두 개 만들었습니다.
| 파일 | 만든 방법 | 크기 | 뽑히는 글자 수 |
|---|---|---|---|
| 글자 PDF | 엑셀에서 PDF로 내보내기 | 75,194바이트 | 686자 |
| 스캔본 흉내 PDF | 위 PDF를 그림으로 바꿔 다시 PDF에 넣음 | 6,533,732바이트 | 0자 |
스캔본 쪽을 열어 보면 A4 한 쪽에 1241×1754px짜리 PNG 한 장이 들어 있습니다. 계산하면 150dpi입니다. 글자는 한 자도 뽑히지 않고 pdfplumber가 세는 글자 상자(chars)도 0개입니다. 스캐너나 휴대폰으로 만든 PDF가 이 상태일 수 있습니다. 다만 요즘은 스캔하면서 글자 인식까지 해 주는 기기도 있으니, 받은 파일이 어느 쪽인지는 열어서 글자가 긁히는지 보셔야 합니다.
방법 1 — 엑셀의 「데이터 가져오기 > PDF에서」 (먼저 이것부터)
엑셀 리본에서 데이터 > 데이터 가져오기 > 파일에서(F) > PDF에서(P) 입니다.

저희는 메뉴가 있는 것까지만 화면으로 확인하고, 옮기는 일은 이 기능이 쓰는 파워 쿼리 식을 그대로 돌려서 숫자를 쟀습니다.
let Source = Pdf.Tables(File.Contents("...\P1_원본표.pdf"), [Implementation="1.3"]),
Tb = Table.SelectRows(Source, each [Kind] = "Table"),
First = Tb{0}[Data]
in First결과는 23행 6열이었습니다. 첫 줄은 Column1~Column6이라는 임시 머리글이고, 그 아래로 원본 표가 들어왔습니다.
- 데이터 행 20개 — 맞음
- 수량 합 251 — 맞음
- 금액 합 6,093,800 — 맞음
- 원본과 다른 칸은 132칸 중 2칸. 둘 다 합계 행입니다. 원본은 A~C를 병합해 첫 칸에 「합계」가 있는데, 결과에서는 「합계」가 3열로 들어갔습니다
- 품목 칸의 줄바꿈은 그대로 남았습니다
방법 2 — 워드로 PDF 열기
워드는 PDF를 열 때 편집할 수 있는 문서로 바꿉니다. 저희가 시험한 PDF에서는 표가 워드 표 1개로 들어왔습니다. 자동화(COM)로 워드를 띄워 그 표를 읽고, 읽은 값을 엑셀 파일로 저장해 숫자를 쟀습니다.
글자 PDF는 여는 데 45.7초 걸렸고, 표를 1개(22행 6열) 찾았습니다.
- 데이터 행 20개, 수량 합 251, 금액 합 6,093,800 — 모두 맞음
- 원본과 다른 칸 3개. 전부 합계 행입니다. 원본은 A~C가 병합돼 있는데, 결과에서는 수량이 4열에서 2열로, 금액이 6열에서 4열로 두 열씩 밀렸습니다
원본 : 합계 | | | 251 | | 6,093,800
결과 : 합계 | 251 | | 6,093,800 | |- 품목 칸의 줄바꿈은 사라졌습니다.
A4 복사용지(80g, 2500매)한 줄이 됐습니다
합계 행은 옮긴 뒤 눈으로 한 번 보셔야 합니다. 데이터 행 20개는 멀쩡한데 마지막 줄만 어긋납니다.
방법 3 — pdfplumber (같은 모양 PDF를 여러 개 반복할 때)
파이썬이 깔려 있고 같은 서식의 PDF가 매달 온다면 이 방법이 편합니다. 한두 번 할 일이면 방법 1부터 해 보시면 됩니다.
pip install pdfplumber openpyxlimport pdfplumber, openpyxl
with pdfplumber.open(r"C:\경로\내파일.pdf") as pdf:
table = pdf.pages[0].extract_table()
wb = openpyxl.Workbook()
ws = wb.active
for row in table:
ws.append(["" if v is None else v for v in row])
wb.save(r"C:\경로\결과.xlsx")글자 PDF에서는 22행 6열을 그대로 가져왔고, 132칸 중 다른 칸이 하나도 없었습니다. 세 방법 중 원본과 가장 가까웠습니다(pdfplumber 0칸, 엑셀 2칸, 워드 3칸). 합계 행도 열 위치를 지켰습니다.
["합계", null, null, "251", "", "6,093,800"]병합된 부서 칸은 null(빈칸)로 들어옵니다. 데이터 20행 중 16행의 부서가 비어 있었습니다. 화면에서 보이는 그대로라 틀린 것은 아니지만, 정렬이나 피벗을 하시려면 위 칸 값을 아래로 채워야 합니다.
세 방법 모두 걸린 함정 — 금액이 「글자」로 들어온다
옮긴 파일 세 개를 열어 금액 열의 자료형을 확인했습니다.
| 방법 | 금액 첫 칸 | 자료형 | 20칸 중 숫자 | 엑셀 SUM 결과 |
|---|---|---|---|---|
| 엑셀 PDF에서 | 258,000 | 글자 | 0개 | 0 |
| 워드로 열기 | 258,000 | 글자 | 0개 | 0 |
| pdfplumber | 258,000 | 글자 | 0개 | 0 |
PDF 안에 있는 258,000은 쉼표가 낀 글자 덩어리입니다. 이번 시험에서는 세 방법 모두 그대로 글자로 넘겨받았습니다. 합계를 잡으면 0이 나오고, 화면에는 숫자처럼 보여서 알아채기 어렵습니다. 비어 있지 않은 칸을 세는 COUNTA는 20이 나오는데 숫자 칸을 세는 COUNT는 0입니다.

고치는 법은 간단합니다.
- 수량·단가·금액 열을 끕니다
- Ctrl+H로
,를 찾아 빈칸으로 바꿉니다
저희가 잰 결과는 이 두 단계로 끝났습니다. 쉼표를 지우는 순간 엑셀이 알아서 숫자로 받았습니다.
손대기 전 : F2 = '258,000' (글자) SUM(F2:F21) = 0 COUNT = 0 COUNTA = 20
쉼표 제거 : F2 = 258000 (숫자) SUM(F2:F21) = 6093800
이어서 F2:F22 에 텍스트 나누기 적용 후 : SUM(F2:F21) = 6093800, COUNT = 20, SUM(D2:D21) = 251쉼표를 지워도 왼쪽 위에 초록 세모가 남고 글자로 버티는 칸이 있으면, 그 열을 잡고 데이터 > 텍스트 나누기에서 바로 「마침」을 누르시면 됩니다. 저희는 이어서 자동화 명령(Range.TextToColumns)으로 같은 일을 시켜 봤고, 숫자 20칸과 수량 합 251까지 확인했습니다.
스캔본 PDF는 어떻게 되나
여기서 세 방법이 갈립니다.
pdfplumber — 표를 0개 찾습니다. 페이지 글자 수 0, 글자 상자 0개, 그림 1개. 옮길 것이 없으니 엑셀 파일도 만들지 않았습니다.
엑셀 「PDF에서」 — 쿼리는 등록되지만 새로 고침에서 멈춥니다.
[Expression.Error] 열거형에 요소가 너무 적어 작업을 완료할 수 없습니다.저희가 쓴 식은 표로 분류된 결과 중 첫 번째를 꺼내는 형태(Tb{0}[Data])인데, 꺼낼 것이 없다는 뜻으로 읽힙니다. 중간 결과까지 찍어 보지는 않았습니다.
워드 — 여기가 위험합니다. 워드는 1.7초 만에 열고 표를 1개(22행 6열) 만들어 냅니다. 글자층이 없는 PDF인데도 글자가 나왔습니다. 그런데 그 숫자가 틀립니다.
| 항목 | 원본 | 워드가 읽은 값 |
|---|---|---|
| 번호가 남아 있는 데이터 행 | 20 | 17 |
| 수량 합 | 251 | 190 |
| 금액 합 | 6,093,800 | 5,122,000 |
| 원본과 다른 칸 | — | 132칸 중 14칸 |

틀린 칸 14개를 그대로 옮기면 이렇습니다.
1행 3열: '품목' -> ''
2행 1열: '1' -> ''
2행 2열: '총무팀' -> '종무팀'
7행 2열: '영업팀' -> '영업 팀'
9행 4열: '11' -> ''
11행 4열: '18' -> ''
12행 1열: '11' -> ''
15행 1열: '14' -> ''
16행 4열: '10' -> ''
18행 3열: '청소용 물티슈' -> '정소용 물티슈'
20행 3열: '커피 원두 1kg' -> '커피 원두 Ikg'
22행 2열: '' -> '251'
22행 4열: '251' -> '6,093.800'
22행 6열: '6093800' -> ''데이터 칸에서 숫자 여섯 칸이 통째로 비었고(합계 행의 금액까지 세면 일곱 칸), 합계 금액은 쉼표가 마침표로 바뀌어 6,093.800이 됐습니다. 한글은 총무팀이 종무팀, 청소용이 정소용, 숫자 1이 알파벳 I로 읽혔습니다.
표가 만들어졌다는 것과 숫자가 맞다는 것은 다른 이야기입니다. 스캔본을 옮기셨다면 행 수와 합계를 원본과 반드시 대조하셔야 합니다.
스캔본에는 글자 인식(OCR)이 필요합니다
앞의 결과가 그 이유입니다. 이번 스캔본 PDF 안에는 글자가 한 자도 없고 사진 한 장만 있습니다. 표를 옮기려면 사진 속 모양을 보고 글자를 알아맞히는 과정, 곧 글자 인식(OCR)을 먼저 거쳐야 합니다.
워드는 1.7초 만에 글자가 든 표를 내놨습니다. 안에서 어떤 인식 과정을 거쳤는지는 저희가 확인하지 않았습니다. 다만 결과가 말해 주듯 이런 작업은 맞히는 일입니다. 같은 워드가 글자 PDF에서는 132칸 중 3칸만 어긋났는데 스캔본에서는 14칸이 어긋났고, 금액 합이 15% 넘게 틀렸습니다.
스캔본을 다뤄야 한다면 순서는 이렇게 잡으시는 편이 안전합니다.
- 원본을 준 쪽에 글자가 들어 있는 PDF나 엑셀 파일을 다시 요청합니다
- 그게 안 되면 OCR을 거치되, 옮긴 뒤 행 수와 합계를 원본과 맞춰 봅니다
- 금액이 걸린 표라면 한 줄씩 눈으로 대조하는 시간을 일정에 넣습니다
결과 — 어떤 경우에 무엇을 쓰면 되나
| 상황 | 쓸 방법 | 왜 |
|---|---|---|
| 글자가 든 PDF, 한두 번 할 일 | 엑셀 데이터 > 데이터 가져오기 > 파일에서 > PDF에서 | 엑셀만 있으면 되고, 132칸 중 2칸만 어긋났습니다(합계 행) |
| 글자가 든 PDF, 표 말고 본문도 손봐야 할 때 | 워드로 PDF 열기 후 표를 엑셀로 | 문서 형태로 바뀌어 손보기 쉽습니다. 다만 병합된 합계 행에서 열이 밀립니다 |
| 같은 서식 PDF가 매달 여러 개 올 때 | pdfplumber | 132칸 전부 일치. 열 위치를 지켜서 반복 처리에 맞습니다 |
| 어느 방법을 쓰든 금액·수량 열 | 옮긴 뒤 Ctrl+H로 쉼표 제거(안 되면 텍스트 나누기) | 이번 시험에서는 세 방법 모두 숫자가 글자로 들어왔습니다. 안 고치면 SUM이 0입니다 |
| 부서·항목이 세로로 병합된 표 | 옮긴 뒤 빈칸에 위 값 채우기 | 병합된 칸은 첫 줄에만 글자가 오고 나머지는 빕니다(20행 중 16행) |
| 스캔본·사진 PDF | 되돌려 받기를 먼저, 안 되면 OCR + 전수 대조 | pdfplumber는 표 0개, 엑셀은 오류, 워드는 합계가 6,093,800 대신 5,122,000 |
| 회사 자료 | 위 세 가지 모두 내 컴퓨터에 있는 파일을 여는 절차입니다 | 변환 사이트에 올리는 단계가 없습니다 |
실패한 것
- 워드를 자동화로 처음 띄웠을 때
Documents.Open(pdf, ConfirmConversions=False, ReadOnly=True, Visible=False)가 COM 오류로 끝났습니다. 이 첫 실행만 로그 파일로 받아 두지 못해 화면에서 본 것만 남았습니다. 오류 문구는 로그가 없으니 여기 옮기지 않습니다. - 그 뒤로는 같은 파일에 대해
Open이 60초가 지나도 돌아오지 않았습니다. 워드를 보이게 띄워 놓고 5초마다 창 목록을 찍어 보니, 60초 내내NUIDialog창 두 개가 떠 있었습니다. 그 창을 그림으로 떠서 읽으니 「마지막으로 'P1_원본표.pdf'을(를) 열었을 때 오류가 발생했습니다. 그래도 이 문서를 여시겠습니까?」였습니다. 그림은 원자료 폴더에P1_word_dialog_1.png로 함께 뒀습니다. - 이름이 다른 파일(
P1_워드용_글자.pdf)을 열었을 때는 45.7초 만에 열렸습니다. 파일 이름이 달라진 것이 원인인지는 확인하지 못했습니다. - 뒤에 같은
ReadOnly=True옵션으로 다시 돌렸더니 그때는 그냥 열렸습니다(표 1개). 그래서 첫 실패를ReadOnly탓으로 단정하지 못합니다. - 그림용 엑셀 파일을 만들면서 openpyxl에
=SUM(F4:F23) →라는 글자를 넣었습니다.=로 시작하면 openpyxl이 수식(data_type='f')으로 저장하는데, 잘못된 수식이라 엑셀이 파일을 열지 못했습니다(Workbooks 클래스 중 Open 메서드에 오류가 있습니다).=를 떼고 다시 만드니 열렸습니다. - 칸 대조를 처음 돌릴 때 띄어쓰기를 무시하도록 짜 두어, 워드가 스캔본에서
영업팀을영업 팀으로 읽은 것을 놓쳤습니다. 다시 세어 13칸에서 14칸으로 고쳤습니다.
확인하지 않은 것
- 워드가 스캔본에서 글자를 어떻게 뽑았는지는 확인하지 않았습니다. 글자층이 없는 PDF에서 글자가 나온 사실만 봤습니다.
- 엑셀 「PDF에서」는 메뉴가 있는 것까지만 화면으로 봤습니다. 메뉴를 눌러 파일을 고르고 탐색 창에서 표를 고르는 화면은 거치지 않고, 같은 기능의 파워 쿼리 식으로 돌렸습니다.
- 워드도 화면에서 파일 > 열기로 PDF를 여는 경로는 눌러 보지 않았습니다. 자동화로만 열었습니다. 워드 표를 마우스로 복사해 엑셀에 붙였을 때 결과가 같은지도 확인하지 않았습니다.
- 각 방법이 통신을 하는지 네트워크를 들여다보지는 않았습니다. 저희가 쓴 명령의 입력·출력 경로가 모두 내 컴퓨터 안이라는 것까지만 확인했습니다.
- 스캔본은 글자 PDF를 150dpi 그림으로 바꿔 만든 흉내입니다. 실제 스캐너로 뜬 파일은 쓰지 않았습니다. 종이가 기울거나 얼룩이 있는 경우는 더 나쁠 수 있습니다.
- 표가 여러 쪽에 걸쳐 이어지는 PDF, 표 안에 표가 든 PDF는 시험하지 않았습니다.
- 테두리가 없는 표는 시험하지 않았습니다. 시험한 표는 132칸 중 130칸에 실선이 있습니다.
- 한글(HWP)로 PDF를 여는 방법은 다루지 않았습니다.
- Excel·Word의 다른 버전, 맥에서는 돌려 보지 않았습니다.