Phase 3 · 비정형 데이터 자동화

이미지 속 영수증을 장부로 변환하다

25단계에서는 엑셀(정형 데이터)을 자동 처리했습니다. 하지만 실제 업무에서는 PDF 세금계산서, 종이 영수증 사진, 카드전표 등 비정형 데이터가 넘쳐납니다.
이번 26단계에서는 OCR(광학 문자 인식) 기술과 AI를 활용해 이미지를 파이썬이 이해할 수 있는 JSON 데이터로 구조화하고 기존 거래장부와 자동 매칭하는 시스템을 구축합니다.

예상 학습 시간 : 180분
난이도 : ★★★★★
사전 단계 : 실무 데이터 전처리 봇 (Step 25)
다음 단계 : 통장·카드·증빙 통합 매칭 (예정)
01

문서 업로드부터 회계사 검토까지의 완벽한 여정

26단계의 목표는 사용자가 무작위로 증빙 파일(PDF, 이미지)을 업로드하면, 파이썬이 내용을 읽고 필요한 필드를 뽑아내어 기존의 회계 장부(엑셀)와 연결해주는 시스템을 완성하는 것입니다.

"증빙파일을 업로드하면 Python이 문서를 읽고 회계에 필요한 데이터를 추출하여 기존 거래자료와 자동으로 연결한다."
PDF / 이미지 ↓ 파일 업로드 ↓ 파일 검증 ↓ OCR (문자 인식) ↓ 텍스트 추출 ↓ 문서 유형 분류 (AI/Rule) ↓ 필드 추출 (공급가액, 사업자번호 등) ↓ 데이터 정제 ↓ 거래자료 매칭 ↓ 금액 검증 및 중복 검증 ↓ AI 보완 분석 ↓ 회계사 최종 검토

이 과정을 거치면 종이에 적힌 다음과 같은 정보가:

공급자: ABC상사
사업자등록번호: 123-45-67890
공급받는자: XYZ주식회사
작성일자: 2026-03-15
공급가액: 10,000,000 / 부가세: 1,000,000 / 합계금액: 11,000,000

파이썬이 다루기 쉬운 구조화된 JSON으로 완벽히 치환됩니다.

02

PDF라고 모두 OCR이 필요한 것은 아니다

PDF는 크게 두 가지로 나뉩니다. 전자적으로 생성된 텍스트 PDF와 스캔 장비로 만들어진 이미지 PDF입니다. 텍스트 PDF는 무거운 OCR 엔진을 돌릴 필요 없이 바로 글자를 빼낼 수 있습니다.

🐍 python (pypdf 활용)
from pypdf import PdfReader

reader = PdfReader("invoice.pdf")
text = ""

for page in reader.pages:
    text += page.extract_text() or ""

if not text.strip():
    print("이 파일은 스캔본(이미지 PDF)입니다. OCR 처리가 필요합니다.")
else:
    print("텍스트 추출 성공:", text)
성능 최적화의 첫걸음

텍스트 추출이 가능한 전자 문서에 OCR을 태우는 것은 엄청난 리소스 낭비입니다. 항상 extract_text()를 먼저 시도하고, 실패했을 때만 OCR로 넘어가는 로직을 구성해야 합니다.

03

OCR 엔진 구동과 한계점 (Tesseract)

스캔된 영수증이나 이미지 PDF를 만났다면, 이미지를 문자로 변환해야 합니다. 가장 대표적인 오픈소스 OCR 엔진인 Tesseract를 사용합니다.

🐍 python (pytesseract)
import pytesseract
from PIL import Image

# 영수증 이미지에서 한글+영어 복합 추출
ocr_text = pytesseract.image_to_string(Image.open("receipt.png"), lang="kor+eng")
print(ocr_text)
OCR의 치명적 한계

OCR은 완벽하지 않습니다. 10,000,00010,000,OOO (알파벳 O)로 읽거나, ABC상사ABC상人으로 오인식할 수 있습니다. 절대로 OCR 결과를 그대로 회계 장부에 때려 박아서는 안 됩니다. 반드시 후처리 정제와 상호 검증(Validation)이 필요합니다.

04

데이터 정제: 정규표현식(Regex)과 라벨 기반 추출

OCR이 토해낸 거친 텍스트 속에서 우리가 원하는 알맹이(사업자번호, 날짜, 금액)만 핀셋처럼 집어내기 위해 정규표현식을 사용합니다.

🐍 python (Regex)
import re

text = "공급가액: 10,000,000원 / 부가세: 1,000,000원"

# [사업자번호 추출 패턴] 000-00-00000
biz_num = re.findall(r"\d{3}[- ]?\d{2}[- ]?\d{5}", text)

# [날짜 추출 패턴] 2026-03-15
dates = re.findall(r"\d{4}[-./]\d{1,2}[-./]\d{1,2}", text)

하지만 단순히 숫자를 추출([\d,]+)하는 것만으로는 부족합니다. 전화번호, 날짜, 금액이 모두 숫자이기 때문입니다. "공급가액"이라는 라벨 주변의 숫자를 잡는 특수 함수를 만들어야 실무에 적용할 수 있습니다.

🐍 python (라벨 기반 추출 함수)
def extract_amount(text, keyword):
    # keyword(예: '부가세') 뒤에 등장하는 최대 20글자 이내의 숫자 덩어리 획득
    pattern = keyword + r".{0,20}?([\d,]+)"
    match = re.search(pattern, text)
    
    if match:
        return int(match.group(1).replace(",", ""))
    return None

supply = extract_amount(text, "공급가액")  # 10000000
vat = extract_amount(text, "부가세")     # 1000000
total = extract_amount(text, "합계")       # 11000000

# [강력한 상호 검증 로직]
if supply + vat == total:
    print("✓ OCR 금액 신뢰도 100%")
else:
    print("⚠ 금액 검토 필요 (OCR 오인식 의심)")
05

문서 분류: 빠르고 저렴한 Rule Engine과 똑똑한 AI의 조합

업로드된 문서가 '세금계산서'인지, '식당 영수증'인지 파악해야 알맞은 필드 추출 로직을 가동할 수 있습니다. 25단계와 마찬가지로 "명확한 건 Python이, 애매한 건 AI가" 원칙을 준수합니다.

# 1차 파이썬 Rule Engine (0원)
def classify_document(text):
    if "세금계산서" in text or ("공급가액" in text and "부가세" in text):
        return "tax_invoice"
    if "거래명세서" in text:
        return "statement"
    return "unknown" # 알 수 없는 문서만 AI에게 토스

# 2차 AI 프롬프트 (비용 발생)
"다음 문서를 분석하여 [tax_invoice, receipt, card_receipt, bank_statement] 중 하나의 JSON으로 분류하시오."
06

거래자료와 증빙의 계층적 자동 매칭

구조화된 증빙 데이터를 얻었다면, 25단계에서 만든 transactions 엑셀 장부와 매칭시킵니다. 데이터의 불완전성을 대비해 가장 빡센 조건부터 느슨한 조건 순서로 계층적 매칭을 수행합니다.

  • 1순위 (가장 확실함) : 사업자번호 + 금액 + 날짜 (모두 일치)
  • 2순위 (날짜가 며칠 빗나감) : 사업자번호 + 금액 일치, 날짜는 ±3일 이내 허용
  • 3순위 (사업자번호 누락) : 거래처명 + 금액 + 날짜 일치
  • 최후의 수단 : AI 유사도 분석 위임
07

파일 지문(Hash)을 이용한 악성 중복 방어

고객이 똑같은 PDF 세금계산서를 이름만 바꿔서 2번 올리면 이중으로 비용 처리되는 사고가 날 수 있습니다. 파일의 고유 지문인 SHA-256 Hash 알고리즘을 사용하여 원천 차단합니다.

🐍 python
import hashlib

def get_file_hash(filepath):
    h = hashlib.sha256()
    with open(filepath, "rb") as f:
        while chunk := f.read(8192):
            h.update(chunk)
    return h.hexdigest()

# DB에 저장된 과거 증빙 해시값과 대조하여 중복 업로드 차단
08

DB 설계와 Human-in-the-loop

OCR 엔진이 추출한 데이터를 100% 맹신해선 안 됩니다. 반드시 원본 파일, OCR 원시 텍스트, 그리고 추출된 구조화 데이터를 모두 DB에 저장하여, 오류 발생 시 회계사가 추적/수정할 수 있게 해야 합니다.

┌─────────────────────────────────────┐ │ AI 증빙 자동검토함 │ ├─────────────────────────────────────┤ │ 파일 invoice_001.pdf │ │ 문서유형 세금계산서 │ │ │ │ [추출 데이터] │ │ 공급자 ABC상사 │ │ 작성일자 2026-03-15 │ │ 공급가액 10,000,000원 │ │ │ │ 금액검증 ✓ 정상 (공급+부가=합계) │ │ 거래매칭 ✓ 성공 (장부내역 일치) │ │ │ │ AI 신뢰도 98% │ │ │ │ [승인 확정] [수정 필요] │ └─────────────────────────────────────┘

[자동 승인 조건]: AI 신뢰도가 95%를 넘고, 공급가액+부가세==합계 수학적 검증을 통과했으며, 장부와 매칭이 완벽한 건에 대해서만 "자동 처리 완료"로 넘기고, 나머지는 "회계사 검토 필요" 상자에 분류해 두는 것이 진정한 업무 자동화 플랫폼의 가치입니다.

09

27단계 예고: 흩어진 자료의 대통합

25단계에서는 엑셀 장부를 다루었고, 이번 26단계에서는 비정형 영수증/PDF를 해독했습니다.
다음 27단계에서는 이 두 세계를 합쳐, "세금계산서 ➡️ 은행 통장 입출금 내역 ➡️ 법인카드 명세서"를 하나의 거대한 트랜잭션 단위로 묶어내어 입출금 오류를 샅샅이 뒤지는 "통합 매칭 엔진"을 구축해보겠습니다.

Step 25 : 실무 데이터 전처리 봇 Phase 3 후반부 공사중