web-dev-qa-db-ja.com

Excelのセル値を読み取り、それを計算する式ではなく-openpyxl

Openpyxlを使用してセル値を読み取ります(ExcelアドインWebサービスはこの列を更新します。)

利用した data_only = Trueただし、現在のセル値は表示されず、Excelが最後にシートを読み取ったときに保存された値です。

wbFile = openpyxl.load_workbook(filename = xxxx,data_only=True)
wsFile = wbFile[c_sSheet]

セルの実際の値を読み取るにはどうすればよいですか?

34
user3411047
wb = openpyxl.load_workbook(filename, data_only=True)

data_onlyフラグが役立ちます。

96
Marcin Kajzler

@ alex-martelliが言うように、openpyxlは式を評価しません。 openpyxlでExcelファイルを開くと、数式を読むか、最後に計算された値を読むかを選択できます。あなたが示すように、数式がアドインに依存している場合、キャッシュされた値は決して正確ではありません。ファイル仕様外のアドインとしてはサポートされません。代わりに、Excelランタイムと対話できる xlwings のようなものを見たいかもしれません。

10
Charlie Clark

同じ問題に直面した。これらのセルが何であれ、セル値を読み取る必要がありました。スカラー、事前計算された値を持つ式、またはそれらのない式、正確さよりもフェールトレランスが優先されます。

戦略は非常に簡単です。

  1. セルに数式が含まれていない場合、セルの値を返します。
  2. 数式の場合は、事前に計算された値を取得してください。
  3. できなかった場合は、 pycel ;を使用して評価してみてください。
  4. 失敗した場合(pycelの式のサポートが制限されているため、またはエラーが発生した場合)、警告してNoneを返します。

このすべての機構を隠し、セル値を読み取るためのシンプルなインターフェイスを提供するクラスを作成しました。

フェールトレランスよりも正確さが望ましい場合、ステップ4で例外を発生させるようにクラスを変更するのは簡単です。

それが誰かを助けることを願っています。

from traceback import format_exc
from pathlib import Path
from openpyxl import load_workbook
from pycel.excelcompiler import ExcelCompiler
import logging


class MESSAGES:
    CANT_EVALUATE_CELL = ("Couldn't evaluate cell {address}."
                          " Try to load and save xlsx file.")


class XLSXReader:
    """
    Provides (almost) universal interface to read xlsx file cell values.

    For formulae, tries to get their precomputed values or, if none,
    to evaluate them.
    """

    # Interface.

    def __init__(self, path: Path):
        self.__path = path
        self.__book = load_workbook(self.__path, data_only=False)

    def get_cell_value(self, address: str, sheet: str = None):
        # If no sheet given, work with active one.
        if sheet is None:
            sheet = self.__book.active.title

        # If cell doesn't contain a formula, return cell value.
        if not self.__cell_contains_formula(address, sheet):
            return self.__get_as_is(address, sheet)

        # If cell contains formula:
        # If there's precomputed value of the cell, return it.
        precomputed_value = self.__get_precomputed(address, sheet)
        if precomputed_value is not None:
            return precomputed_value

        # If not, try to compute its value from the formula and return it.
        # If failed, report an error and return empty value.
        try:
            computed_value = self.__compute(address, sheet)
        except:
            logging.warning(MESSAGES.CANT_EVALUATE_CELL
                            .format(address=address))
            logging.debug(format_exc())
            return None
        return computed_value                

    # Private part.

    def __cell_contains_formula(self, address, sheet):
        cell = self.__book[sheet][address]
        return cell.data_type is cell.TYPE_FORMULA

    def __get_as_is(self, address, sheet):
        # Return cell value.
        return self.__book[sheet][address].value

    def __get_precomputed(self, address, sheet):
        # If the sheet is not loaded yet, load it.
        if not hasattr(self, '__book_with_precomputed_values'):
            self.__book_with_precomputed_values = load_workbook(
                self.__path, data_only=True)
        # Return precomputed value.
        return self.__book_with_precomputed_values[sheet][address].value

    def __compute(self, address, sheet):
        # If the computation engine is not created yet, create it.
        if not hasattr(self, '__formulae_calculator'):
            self.__formulae_calculator = ExcelCompiler(self.__path)
        # Compute cell value.
        computation_graph = self.__formulae_calculator.gen_graph(
            address, sheet=sheet)
        return computation_graph.evaluate(f"{sheet}!{address}")
3
krvkir

@Charlie Clarkが述べたように、xlwingsを使用できます(MS Excelがある場合)。ここに例

数式を含むExcelシートがあるとします。例では、openpyxlで定義します

from openpyxl import Workbook, load_workbook
wb=Workbook()

ws1=wb['Sheet']

ws1['A1']='a'
ws1['A2']='b'
ws1['A3']='c'

ws1['B1']=1
ws1['B2']=2
ws1['B3']='=B1+B2'

wb.save('to_erase.xlsx')

前述のように、openpyxlを使用してExcelを再度ロードすると、評価された式は取得されません。

wb2 = load_workbook(filename='to_erase.xlsx',data_only=True)
wb2['Sheet']['B3'].value

xlwingsを使用して、Excelで評価された数式を取得できます。

import xlwings as xw
wbxl=xw.Book('to_erase.xlsx')
wbxl.sheets['Sheet'].range('B3').value

期待値3を返します。

非常に複雑な数式やシート間の参照を含むスプレッドシートを操作するときに、非常に便利です。

1
Nabla