Python 读取Excel单元格值,而不是计算它的公式-openpyxl

Python 读取Excel单元格值,而不是计算它的公式-openpyxl,python,openpyxl,Python,Openpyxl,我正在使用openpyxl读取单元格值(excel addin webservice)更新此列。 ) 我使用了data\u only=True,但它没有显示当前单元格值,而是Excel上次读取工作表时存储的值 wbFile = openpyxl.load_workbook(filename = xxxx,data_only=True) wsFile = wbFile[c_sSheet] 如何读取单元格的实际值 正如@alex martelli所说,openpyxl不评估公式。使用openpyx

我正在使用openpyxl读取单元格值(excel addin webservice)更新此列。 )

我使用了
data\u only=True
,但它没有显示当前单元格值,而是Excel上次读取工作表时存储的值

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

如何读取单元格的实际值

正如@alex martelli所说,openpyxl不评估公式。使用openpyxl打开Excel文件时,您可以选择读取公式或上次计算的值。如您所示,如果公式依赖于外接程序,则缓存的值永远不会准确。作为文件规范之外的加载项,它们将永远不受支持。相反,您可能希望看到类似这样的东西,它可以与Excel运行时交互

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

data\u only
标志有帮助。

面临同样的问题。需要读取单元格值,无论这些单元格是什么:标量、带有预计算值的公式或不带这些值的公式,容错性优先于正确性

策略非常简单:

  • 如果单元格不包含公式,则返回单元格的值
  • 如果它是一个公式,尝试获取它的预计算值
  • 如果做不到,尝试使用评估工具进行评估
  • 如果失败(由于
    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}")
    

    正如@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


    我发现它在处理具有非常复杂的公式和表格之间的引用的电子表格时非常有用

    我通过以下方式解决了这个问题:

    import xlwings
    from openpyxl import load_workbook
    
    data = load_workbook('PATH_TO_YOUR_XLSX_FILE')
    data['sheet_name']['A1'].value = 1
    data.save('PATH_TO_YOUR_XLSX_FILE')
    
    excel_app = xlwings.App(visible=False)
    excel_book = excel_app.books.open('PATH_TO_YOUR_XLSX_FILE')
    excel_book.save()
    excel_book.close()
    excel_app.quit()
    
    data = load_workbook('PATH_TO_YOUR_XLSX_FILE', data_only=True)
    
    我希望,这可以帮助您…

    有能力评估一个单元格

    from xlcalculator import ModelCompiler
    from xlcalculator import Model
    from xlcalculator import Evaluator
    
    filename = r'xxxx.xlsm'
    compiler = ModelCompiler()
    new_model = compiler.read_and_parse_archive(filename)
    evaluator = Evaluator(new_model)
    val1 = evaluator.evaluate('First!A2')
    print("value 'evaluated' for First!A2:", val1)
    
    输出为:


    值“评估”为第一!A2:0.1

    如果工作表中有“REF!”错误单元格,我发现“仅数据”选项工作不正常。 Openpyxl为我的小测试xlsx文件中的每个单元格值返回None。 对我来说,在打开Excel并修复单元格后,data_只能完美地工作。
    我仅使用openpyxl 3.0.3数据:读取公式单元格的偶数值。

    保留vba:仅当您使用启用宏的excel时才使用它

    file_location = 'C:\Arpan Saini\Monsters\Project_Testing\SecCardGrad\SecCardGrad_Latest_docs\Derived_Test_Cases_Secure_Card_Graduate.xlsm'
    wb = load_workbook(file_location, keep_vba=True, data_only=True)
    

    我不认为
    openpyxl
    复制了Excel巨大的公式求值子系统,所以我认为您不能让它自动重新计算所有公式。最好的情况是,您可以为大型公式语言的子集实现自己的基于
    eval
    的解释器。我不需要计算或执行forumula。我只需要读取单元格值。“单元格值”(超出公式)是Excel保存工作表时保存的值,您暗示它不是您真正想要的值——您想要“当前”值(毫无疑问,取决于其他单元格中的值),这意味着您需要根据其他单元格的当前值重新计算公式!很抱歉让您困惑,实际上我的专栏是通过excel加载项升级的(webservice将轮询数据)。。。我需要提取该列的单元格值。我认为您需要(A)再次使用Excel来重新计算公式,或者通过所说的外接程序,或者类似的方式;或者(B)如果公式足够简单,按照我说的,实现你自己的公式解释器
    openpyxl
    和其他Excel文件的Excel免费阅读器不会执行您需要的公式计算(无论您是否认为需要:-)。是的。这就回答了问题。如果您想同时访问等式和值,那么您可能会得到两个实例,例如
    wb2=openpyxl.load\u工作簿(文件名)
    。然后在读取相应的索引时,您从
    wb
    中获得值,从
    wb2
    中获得方程。嗨,单元格不是空的。这是因为openpyxl不计算公式。我通过获取excel数据并将所有计算放在服务器上解决了这一问题:|可能值得在官方功能跟踪器上添加一个问题,但根据判断,我怀疑这是故意避免的功能:对公式的编辑很难与计算值同步。你必须重新实施整个公式评估系统。这可能会侵犯版权,需要Excel(或OpenOffice)许可证,或者将工作簿限制为有效只读。它不会回答最初的问题吗?在这种情况下,使用xlwings包是一种解决方案。如果data_only=True,cell.value将返回该值(Excel上次写入文件时知道的值)。cell.internal_value将返回公式。关于此答案,有两个问题:(1)如何区分打开XL文件读取forumulae v.s.读取上次计算的值?这是通过
    data\u only=True
    参数实现的吗?(2)
    上次计算的值在现实世界中是什么意思?也就是说,如果XL文件是在最后一次(手动/人工)更改后在退出时保存的,这是否意味着所有单元格都是按其“最后计算值”重新计算的?通常,何时重新计算单元值?(我意识到这比OpenPyXL更像是一个Excel问题,但如果能得到澄清,我将不胜感激)不管怎样,我想我在这里找到了答案:你提到了
    pycel
    。多好的主意啊@Rockallite应该知道,
    pycel
    只支持有限的Excel函数集。但对于简单的情况,它可以很好地工作。只对