Skip to content

Миграция с xlrd

xlrd был стандартной Python-библиотекой для чтения устаревших .xls (Excel 97–2003). В версии 2.0 (2020) он убрал поддержку .xls и рекомендует мигрировать. Обходные пути сообщества — пин xlrd<2.0, вызов LibreOffice, переход на python-calamine — у каждого свои оговорки.

Office Oxide читает .xls напрямую, в 13 раз быстрее последнего релиза xlrd с поддержкой .xls, с более высокой долей успеха. Бонусом можно конвертировать .xls.xlsx одной строкой.

Когда мигрировать

Переходите, если что-то из этого про вас:

  • Вы всё ещё на xlrd<2.0 и хотите поддерживаемую библиотеку
  • Нужны .xls и .xlsx из одной библиотеки
  • Хотите один раз мигрировать корпус в .xlsx и перестать возиться с устаревшим форматом
  • Нужны также .doc, .ppt, .docx или .pptx — покрывается той же установкой

Установка

pip uninstall xlrd
pip install office-oxide

Сравнительная шпаргалка

Открыть .xls

xlrd

import xlrd

book = xlrd.open_workbook("legacy.xls")
sheet = book.sheet_by_index(0)

office_oxide

from office_oxide import Document

with Document.open("legacy.xls") as doc:
    xls = doc.as_xls()
    sheet = xls.sheets()[0]

Итерация по ячейкам

xlrd

for row in range(sheet.nrows):
    for col in range(sheet.ncols):
        print(sheet.cell_value(row, col))

office_oxide

for cell in sheet.cells():
    print(cell.address(), cell.value())

Прочитать все ячейки как таблицу (самый частый случай)

xlrd

import xlrd

book = xlrd.open_workbook("legacy.xls")
sheet = book.sheet_by_index(0)
rows = [
    [sheet.cell_value(r, c) for c in range(sheet.ncols)]
    for r in range(sheet.nrows)
]

office_oxide

from office_oxide import Document

with Document.open("legacy.xls") as doc:
    ir = doc.to_ir()

# Первый лист → первая секция → первая таблица
table = next(el for el in ir["sections"][0]["elements"] if el["kind"] == "Table")
rows = table["rows"]

Имена листов

xlrd

book = xlrd.open_workbook("legacy.xls")
print(book.sheet_names())

office_oxide

with Document.open("legacy.xls") as doc:
    print([s.name() for s in doc.as_xls().sheets()])

Конвертация .xls → .xlsx одной строкой

Если ваша обвязка уже понимает .xlsx, самая чистая миграция — один раз конвертировать корпус и больше не трогать .xls:

from office_oxide import Document

with Document.open("legacy.xls") as doc:
    doc.save_as("modern.xlsx")

Для целого каталога:

from pathlib import Path
from office_oxide import Document

for src in Path("legacy").rglob("*.xls"):
    dst = src.with_suffix(".xlsx")
    with Document.open(src) as doc:
        doc.save_as(dst)

Производительность

Библиотека .xls Среднее p99 Доля успеха
office_oxide 2,8 мс 75 мс 99,2%
python-calamine 9,0 мс 96 мс 90,7%
xlrd 36,6 мс 503 мс 93,1%

Office Oxide в 13 раз быстрее xlrd и имеет долю успеха на 6,1 процентного пункта выше.

Что теряется

Выражения формул xlrd, именованные диапазоны и кэши общих формул не пробрасываются через IR. Кэшированные результаты формул сохраняются — именно это обычно нужно обвязке. Для самих выражений формул спускайтесь в формат-специфичный модуль xls либо конвертируйте в .xlsx и используйте xlsx.

См. также