Skip to content

openpyxl에서 마이그레이션

Office Oxide는 openpyxl보다 XLSX를 18배 빠르게 읽습니다(1,802개 파일 평균 5.0 ms 대 94.5 ms). 테스트한 모든 라이브러리 중 가장 높은 통과율을 보이며, 레거시 .xls도 직접 읽습니다 — openpyxl은 아예 할 수 없는 일입니다.

언제 마이그레이션할까

다음 중 하나라도 한다면 전환하세요:

  • 인제스트 / RAG / 대시보드용으로 .xlsx에서 셀, 행, 시트, 테이블 읽기
  • 스프레드시트를 Markdown이나 HTML로 변환
  • xlrd(2.0부터 .xls에 대해 지원 중단) 추가나 LibreOffice 셸아웃 없이 .xls 지원 필요
  • 의존성을 늘리지 않고 .docx, .pptx 또는 레거시 DOC/PPT도 처리
  • 템플릿의 셀 기록에 EditableDocument 사용

openpyxl에 남는 게 나은 경우:

  • 차트, 조건부 서식, 명명된 스타일, 피벗 테이블을 갖춘 복잡한 XLSX를 처음부터 만든다(openpyxl은 완전 기능 생성에서 가장 강력한 순수 Python 옵션)
  • 순수 Python에서 수식 평가가 필요

설치

pip uninstall openpyxl
pip install office-oxide

비교 치트시트

워크북 열기

openpyxl

from openpyxl import load_workbook

wb = load_workbook("budget.xlsx", data_only=True)

office_oxide

from office_oxide import Document

with Document.open("budget.xlsx") as doc:
    ...

시트 셀 순회

openpyxl

from openpyxl import load_workbook

wb = load_workbook("budget.xlsx", data_only=True)
for sheet in wb.worksheets:
    for row in sheet.iter_rows(values_only=True):
        print(row)

office_oxide

from office_oxide import Document

with Document.open("budget.xlsx") as doc:
    ir = doc.to_ir()

for section in ir["sections"]:
    print(f"# {section.get('title')}")
    for el in section["elements"]:
        if el["kind"] == "Table":
            for row in el["rows"]:
                print(row)

셀 단위의 풍부한 접근(타입, 수식, 병합된 셀)이 필요하면 XLSX 모듈로 내려가세요:

with Document.open("budget.xlsx") as doc:
    xlsx = doc.as_xlsx()
    for sheet in xlsx.sheets():
        for cell in sheet.cells():
            print(cell.address(), cell.value(), cell.value_type())

단일 셀 읽기

openpyxl

wb = load_workbook("budget.xlsx", data_only=True)
sheet = wb["Q4"]
val = sheet["B5"].value

office_oxide

with Document.open("budget.xlsx") as doc:
    val = doc.as_xlsx().sheet("Q4").cell("B5").value()

셀 쓰기(템플릿화)

openpyxl

from openpyxl import load_workbook

wb = load_workbook("template.xlsx")
ws = wb["Summary"]
ws["A1"] = "Total"
ws["B1"] = 42.5
ws["C1"] = True
wb.save("filled.xlsx")

office_oxide

from office_oxide import EditableDocument

with EditableDocument.open("template.xlsx") as ed:
    ed.set_cell(0, "A1", "Total")    # sheet 0 = 첫 번째 시트
    ed.set_cell(0, "B1", 42.5)
    ed.set_cell(0, "C1", True)
    ed.save("filled.xlsx")

sheet_index는 0부터 시작하고, cell_ref는 표준 A1 표기입니다. 시트 이름 → 인덱스를 해결하려면 워크북을 한 번 읽어 sheets()를 호출하세요.

Markdown / HTML로 변환

openpyxl — 내장 없음. 행을 직접 렌더링해야 합니다.

office_oxide

with Document.open("budget.xlsx") as doc:
    md = doc.to_markdown()    # 시트당 ## 섹션 하나, GFM 테이블

시트 이름 읽기

openpyxl

wb = load_workbook("budget.xlsx")
print(wb.sheetnames)

office_oxide

with Document.open("budget.xlsx") as doc:
    print([s.name() for s in doc.as_xlsx().sheets()])

레거시 .xls 읽기

openpyxl은 .xls를 열 수 없습니다. 역사적 우회책은 xlrd였지만 2.0부터 .xls는 지원 중단이며 더 이상 관리되지 않습니다.

office_oxide

from office_oxide import Document

with Document.open("legacy.xls") as doc:
    print(doc.plain_text())
    doc.save_as("modern.xlsx")    # 한 줄 마이그레이션

성능

라이브러리 평균 p99 통과율
office_oxide 5.0 ms 40 ms 97.8%
python-calamine 13.9 ms 183 ms 96.6%
openpyxl 94.5 ms 698 ms 96.2%

하루 10만 개 스프레드시트를 읽는 일반적인 분석 파이프라인: openpyxl로 8시간 18분, office_oxide로 26분.

잃는 것

EditableDocument.set_cell은 원시 셀 값을 씁니다. 숫자 형식, 조건부 서식, 차트, 명명된 범위는 수정하지 않습니다(해당 부분은 그대로 보존됩니다). 완전한 스타일링으로 XLSX를 구성하려면 openpyxl을 사용하거나 office_oxide.xlsx::create::XlsxBuilder로 내려가세요.

관련 항목