簡體   English   中英

讀取 Excel 單元格值而不是計算它的公式 -openpyxl

[英]Read Excel cell value and not the formula computing it -openpyxl

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

我使用data_only = True但它沒有顯示當前單元格值,而是 Excel 上次讀取工作表時存儲的值。

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

如何讀取單元格實際值?

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

data_only標志有幫助。

正如@alex-martelli 所說,openpyxl 不評估公式。 當您使用 openpyxl 打開 Excel 文件時,您可以選擇讀取公式或最后計算的值。 如果如您所指,公式依賴於加載項,則緩存值永遠不會准確。 作為文件規范之外的加載項,它們將永遠不受支持。 相反,您可能想查看可以與 Excel 運行時交互的xlwings之類的東西。

data_only :甚至為公式單元格讀取值。

keep_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)

正如@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. 如果單元格不包含公式,則返回單元格的值;
  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}")

我通過以下方式解決了這個問題:

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)

我希望,這可以幫助你...

如果有“REF!”,我發現 data_only 選項無法正常工作。 工作表中的錯誤單元格。 Openpyxl 為我的小測試 xlsx 文件中的每個單元格值返回 None 。 對我來說,在打開 Excel 並修復單元格后,data_only 可以完美運行。 我使用 openpyxl 3.0.3

我沒有使用 Python 庫來進行 Excel 計算,而是讓 Excel 來進行計算。

為什么? 它不是純 Python,但它最大限度地減少了涉及的 Python 數量。 我沒有使用 Python 來評估 Excel 公式,而是讓 Excel 處理它自己的功能。 這避免了評估 Excel 公式的 Python 中任何可能的錯誤。 以下概述了這種方法的工作原理:

  1. 使用 data_only=False 調用 openpyxl 進行編輯,然后保存電子表格。
  2. 使用 subprocess.Popen 在 Excel 中打開新電子表格,並讓 Excel 評估電子表格公式。
  3. 使用 pynput.keyboard 保存更新的電子表格並退出 Excel。
  4. 使用帶有 data_only=True 的 openpyxl 打開更新的電子表格並獲取公式的值。

這是一個 Windows 測試程序,它創建一個新工作簿,將公式“=SUM(Al:C3)”放入單元格 E2,將數據放入單元格 A1-C3,然后計算公式。

from openpyxl import load_workbook, Workbook
from pynput.keyboard import Key, Controller
import subprocess
import time
import os

excel_prog = r'C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE'

# Create test Excel workbook, get default worksheet.
wb = Workbook()
ws = wb.active

# Put data and a formula into worksheet.
for row_index in range(1,4):
    for column_index in range(1,4):
        ws.cell(row = row_index, column = column_index).value = row_index + column_index
ws['E1'].value = 'Sum of cells in range A1:C3:'
ws['E2'].value = '=SUM(A1:C3)'

# Try to get value of formula.  We'll see the formula instead.
print('E2:', ws['E2'].value)

# Save and close workbook.
wb.save(filename = 'test.xlsx')
wb.close()

# Pause to give workbook time to close.
time.sleep(5)

# Open the workbook in Excel.  I specify folder, otherwise Excel will
# open in "Protected View", interfering with using pynput.
subprocess.Popen([excel_prog, os.path.join(os.getcwd(), 'test.xlsx')])

# Pause to give workbook time to open and for formulas to update.
time.sleep(5)

# Save workbook using pynput.
keyboard = Controller()
with keyboard.pressed(Key.ctrl):
    keyboard.press('s')
    keyboard.release('s')

# Pause to give workbook time to save.
time.sleep(5)

# Close workbook.
with keyboard.pressed(Key.alt):
    keyboard.press(Key.f4)
    keyboard.release(Key.f4)

# Pause to give workbook time to fully close.
time.sleep(5)

# Open Excel workbook and worksheet in openpyxl, data-only.
wb = load_workbook(filename = 'test.xlsx', data_only = True)
ws = wb.active

# Get value of the cell containing the formula.
print('E2:', ws['E2'].value)

# Close workbook.
wb.close()

在 openpyxl 上,使用 xlwings。

Xlcalculator具有評估單元格的能力。

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)

輸出是:

First!A2 的“評估”值:0.1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM