Skip to content

从 openpyxl 迁移

Office Oxide 读取 XLSX 比 openpyxl 快 18 倍(1,802 个文件,平均 5.0 ms 对 94.5 ms),通过率高于所有测试过的库。它还能直接读取遗留 .xls — openpyxl 根本做不到。

何时迁移

如果你在做下列任何一项,就切换:

  • .xlsx 读取单元格、行、工作表或表格用于数据摄取 / RAG / 仪表盘
  • 将电子表格转换为 Markdown 或 HTML
  • 需要 .xls 支持,但不想添加 xlrd(自 2.0 起已弃用)或调用 LibreOffice
  • 想用同一个库处理 .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 从零开始;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

相关链接