업무자동화

엑셀 수식 분석기 만들기 ① 엑셀을 열지 않고 수식 읽기

피노K

2026년 10월 25일, 엑셀을 열지 않고 구조와 수식을 읽는 로컬 분석기를 만들기 시작했습니다. 10월 31일에는 xlsx·xlsm·xlsb·xls 네 형식을 모두 읽게 됐습니다. 합성 파일에서 xlsb·xlsm으로 복원한 수식 133개가 xlsx 원문과 전부 일치했습니다.

시작한 이유는 인수인계가 끊긴 업무 엑셀이었습니다. 시트가 수십 개에 수식이 수십만 칸이고, 파워쿼리와 매크로까지 섞여 있었습니다. 어디서 숫자가 시작해 어디로 가는지 알 길이 없었습니다.

그렇다고 외부 AI에 통째로 올릴 수도 없었습니다. 안에 고객 정보와 회사 숫자가 들어 있기 때문이죠.

먼저 결론

  • 첫 구상안의 "개인정보를 지운 사본부터"와 "AI가 오류를 판정"은 뒤로 미루고, 읽기 전용 구조 추출부터 만들었습니다.
  • 첫 버전은 Python 표준 라이브러리만으로 xlsx·xlsm을 읽고, 원본이 바뀌지 않았는지 해시로 확인합니다.
  • 파일을 고르고 결과를 보는 로컬 화면을 붙였고, 127.0.0.1 밖으로는 열리지 않게 했습니다.
  • xlsb·xls의 수식은 글자가 아니라 이진 토큰으로 저장돼 있어 직접 복원했고, xlsx 원문과 대조했습니다.

AI 판정보다 읽기 전용 추출이 먼저였다

목표는 엑셀 업무 인수인계 분석기였습니다. 분석 엔진이 사실을 추출하고, 설명은 그 근거 위에서만 하게 한다는 원칙을 먼저 정했습니다.

첫 버전이 답할 질문은 세 가지로 좁혔습니다. 어떤 시트와 외부 파일이 서로 연결되는지, 결과 칸이 어떤 수식과 원본 범위에 의존하는지 봅니다. 그리고 무엇이 확인된 사실이고 무엇을 담당자가 확인해야 하는지 나눕니다.

처음 구상안은 달랐습니다. 개인정보를 지운 사본을 먼저 만들고, 같은 사람을 같은 가상값으로 바꾸면 수식이 보존된다고 봤습니다. 파일을 넣으면 AI가 오류를 판정하고, 처음부터 DB와 MCP를 세우는 안이었습니다.

AI 코딩 도구에 이 구상을 주고 개발 계획을 받았습니다. 계획은 네 가지를 모두 뒤로 미루자고 했습니다.

가상값 치환은 정렬·부분 추출·날짜 계산까지 보존하지 못한다는 이유였습니다. 수식 개수가 같다고 의미가 같은 것도 아니었습니다. 다중 사용자 서버는 로컬에서 쓸모를 확인한 뒤에 해도 늦지 않았습니다.

그래서 저는 순서를 바꿨습니다. 로컬에서 읽기 전용으로 구조를 추출하고, 외부 AI가 없어도 구조 보고서까지는 나오게 했습니다. 정제 사본과 서버는 후속으로 돌렸습니다.

2026년 10월 25일에 저장소를 만들고 같은 날 첫 버전에 들어갔습니다.

엑셀 파일은 압축된 XML 묶음이었다

첫 버전은 Python 3.11 이상의 표준 라이브러리만으로 xlsx·xlsm을 읽습니다. 엑셀 파일은 사실 XML 묶음을 압축한 것입니다. 압축을 풀어 XML을 읽으면 시트·수식·이름·연결·피벗·VBA가 있는지 셀 수 있습니다.

명령줄에서 파일을 넣으면 JSON과 HTML 보고서가 나오게 했습니다.

원본을 건드리지 않는다는 조건은 코드로 강제했습니다. 분석 전후 SHA-256 해시를 비교해 보고서에 "원본 불변"을 기록합니다. 엑셀·openpyxl 저장 기능으로 덮어쓰는 경로는 아예 두지 않았습니다.

입력 쪽 방어도 같이 넣었습니다. 부품 크기와 압축비 한도, 중복·위험 경로 거절, XML DTD와 엔터티 거절입니다. 엑셀 파일이라고 믿고 열었다가 압축 폭탄을 만나는 일을 막기 위해서입니다.

검증은 합성 파일로 했습니다. 시트 2개·셀 8개·수식 5개·저장된 오류값 1개짜리 파일입니다. 분석기가 센 숫자와 XML을 직접 센 숫자가 같은지 봤습니다.

단위 테스트 12개가 통과했습니다. 보고서를 크롬 1440px와 390px에서 열어 가로 넘침과 콘솔 오류가 없는 것도 확인했습니다. 이때는 보고서에 시트명·수식 원문·셀 값을 넣지 않는 정책이었습니다.

옛 서버가 살아 있어 새 코드가 안 보였다

명령줄만으로는 쓰기 불편해 같은 날 로컬 화면을 붙였습니다. 브라우저에서 파일을 고르면 같은 PC의 서버가 임시 사본을 읽고, 끝나면 사본을 지웁니다. 보고서는 응답과 브라우저 메모리에만 남고 HTML·JSON으로 저장할 수 있습니다.

로컬이라도 보호 장치는 넣었습니다. 127.0.0.1에만 바인딩하고, Host·Origin과 실행마다 바뀌는 토큰을 검사합니다. 임의 파일을 열어 보는 경로는 두지 않고, 요청과 파일명은 로그에 남기지 않습니다.

분석은 한 번에 한 건만 받습니다. 테스트는 19개로 늘었고, 390px에서도 화면이 깨지지 않는 것을 확인했습니다.

문제는 서버를 다시 띄울 때 생겼습니다. 코드를 고치고 재시작했는데 옛 서버가 그대로 살아 있었습니다. Windows에서 같은 포트에 서버 두 개가 겹쳐 뜬 것입니다.

새 코드가 반영되지 않은 것처럼 보여 한참 헤맸습니다. 원인은 포트를 공유 모드로 열던 설정이었습니다. 독점 바인딩으로 바꿔, 옛 서버가 살아 있으면 새 서버가 뜨지 못하고 오류를 내게 했습니다.

실제 업무 파일은 xlsx보다 xlsb가 많았다

큰 파일은 이진 형식인 xlsb로 저장하는 경우가 많고, 옛 파일은 xls입니다. 그래서 10월 31일에 네 가지 형식을 모두 읽는 심층 분석기로 다시 만들었습니다.

xlsb와 xls는 수식을 글자가 아니라 토큰 배열로 저장합니다. 토큰을 읽어 수식 문장으로 되돌리는 복원기를 직접 썼습니다. 공유 수식, 배열 수식, 표 구조적 참조, 파워쿼리 M 코드, VBA 모듈까지 같이 읽습니다.

이 과정에서 "표준 라이브러리만" 결정을 버렸습니다. xls의 함수 번호표와 읽기는 xlrd가 훨씬 안정적이었습니다. 정리표를 엑셀로 쓰는 일은 openpyxl이 나았습니다.

보고서 정책도 바꿨습니다. 업무 분석을 하려면 시트명·열 제목·수식·M 코드가 보여야 해서 로컬 보고서에는 넣었습니다. 셀 값은 여전히 넣지 않고, 전화·주민번호·이메일·계좌 모양의 글자는 가립니다.

검증은 같은 내용을 네 형식으로 저장한 합성 파일로 했습니다. xlsx의 XML 원문 수식을 기준으로, xlsb와 xlsm에서 복원한 수식 133개가 전부 일치했습니다.

xls는 표 참조 4칸만 달랐습니다. xls에는 표 구조적 참조가 없어 저장할 때 일반 참조로 바뀝니다. 형식 특성이라 저는 문제로 보지 않았습니다.

실제 업무용 xlsb 한 개로도 돌려 봤습니다. 수식 해석 실패가 0이었습니다. 엑셀이 파일 안에 저장해 둔 계산 순서 목록의 셀 수와 분석기가 찾은 수식 칸 수도 같았습니다. 분석은 몇 초 안에 끝났습니다.

바꾼 것과 아직 못 한 것

바꾼 것은 세 가지입니다. 정제 사본과 AI 판정보다 읽기 전용 구조 추출을 먼저 만들었습니다. 표준 라이브러리 원칙은 네 형식 지원 앞에서 버렸습니다. 보고서에는 시트명과 수식은 넣되 값은 넣지 않는 선으로 정책을 옮겼습니다.

못 한 것도 있습니다. VBA는 합성 파일로만 확인했고 실제 매크로 파일로는 돌려 보지 못했습니다. xls의 피벗 원본, 차트와 조건부 서식 안의 수식, 데이터 모델 내부는 이 시점에 읽지 못했습니다.

셀 하나를 골라 거슬러 올라가는 추적 화면도 아직 없습니다.

첫 구상은 AI에 넣으면 알아서 분석해 주는 도구였습니다. 실제로 만든 것은 AI 없이 파일만 읽는 도구였습니다. 수식이 몇 칸인지, 어느 시트가 어느 시트를 읽는지는 AI가 추측할 일이 아니었습니다. 파일에서 세어야 할 사실이었습니다.

다음 편에서는 읽어 낸 수식 목록을 사람이 읽는 업무 규칙서로 바꿉니다. 수식을 파이썬으로 옮겨 엑셀 저장값과 대조한 과정도 이어 갑니다.

'업무자동화' 카테고리의 다른 글