Pandas将Excel(xlsx)文件附加时出现attribute.error错误。

3

如果遇到以下任何一个错误,您需要解决: writer.book=book AttributeError: can't set attribute 'book' 或者 BadZipFile

为了避免出现badzipfile错误,我先加入写入Excel文件的代码行:dataOutput=pd.DataFrame(dictDataOutput,index=[0]) 但是,即使这样做,我仍然无法摆脱 writer.book = book AttributeError: can't set attribute 'book' 的问题。正如Stack Overflow中的一篇答案建议的那样,我需要将openpyxl还原到先前的版本,或者使用CSV文件而不是Excel文件。但我认为这不是解决办法。应该有其他的解决办法,但我找不到。

dataOutput=pd.DataFrame(dictDataOutput,index=[0])
dataOutput.to_excel('output.xlsx') 'output.xlsm'
book = load_workbook('output.xlsx') 'output.xlsm'
writer = pd.ExcelWriter('output.xlsx')OR'output.xlsm'#,engine='openpyxl',mode='a',if_sheet_exists='overlay')
writer.book = book
writer.sheets = {ws.title: ws for ws in book.worksheets}

for sheetname in writer.sheets:
    dataOutput.to_excel(writer,sheet_name=sheetname, startrow=writer.sheets[sheetname].max_row, index = False,header= False)

writer.save()

我在此处查找答案,并在此处中详细解决了AttributeError的问题。

——我尝试了另一种方法。

with pd.ExcelWriter('output.xlsx', mode='a',if_sheet_exists='overlay') as writer:
    dataOutput.to_excel(writer, sheet_name='Sheet1')
    writer.save()

但这次出现了另一个错误

FutureWarning: save is not part of the public API, usage can give in unexpected results and will be removed in a future version

writer.save()

根据@Andrew的评论,我修改了代码如下;

with pd.ExcelWriter('outputData.xlsm', engine='openpyxl', mode='a', if_sheet_exists='overlay') as writer:
    book = load_workbook('outputData.xlsm', keep_vba=True)

    writer.book = book
    writer.sheets = {ws.title: ws for ws in book.worksheets}
    current_sheet = book['Sheet1']
    Column_A = current_sheet['A']
    maxrow = max(c.row for c in Column_A if c.value is not None)

    for sheetname in writer.sheets:
        AllDataOutput.to_excel(writer, sheet_name=sheetname, startrow=maxrow, index=False, header=False)
1个回答

7

有些问题不太清楚,但我会尽力回答您想要做什么。

首先,以下几点是行不通的:

  1. 根据to_excel文档,“如果您希望在工作簿中写入多个工作表,则需要指定ExcelWriter对象”,因此当您运行dataOutput.to_excel('output.xslx')时,您将创建一个仅包含单个工作表的Excel工作簿。稍后,似乎您正在尝试编写多个工作表,但是您只能编写单个工作表,因为这是工作簿一开始就有的全部内容。
  2. ExcelWriter文档中可以看出,.save()已被弃用,应改用.close()。但建议使用上下文管理器(with ... as ... :),以完全避免进行这项操作。
  3. 默认情况下,ExcelWriter使用w(写入)模式,因此您之前遇到的BadZipFile错误可能与运行顺序有关。如果您使用to_excel编写了一本书,然后使用openpyxl加载它,然后再使用ExcelWriter,您将编写、加载,然后立即用空白文件覆盖该文件。如果您随后尝试重新加载该书而没有使用to_excel重新创建它,则会尝试加载空文件,这就是为什么会抛出该错误的原因。

你在问题中链接的答案似乎使用了一个更旧的版本的pandas,其与Excel文件的交互行为有很大的不同。最新版本似乎简化了很多事情!
举个例子,我假设你有两个名为df1和df2的DataFrame,你想将它们写入output.xlsx中的Sheet_1和Sheet_2,并且你想使用名为df3和df4的其他DataFrames更新这些表中的数据(使用overlay选项)。为了确认,我安装了openpyxl = 3.0.10和pandas = 1.5.0。
根据您目前的编写,dataOutput 中没有任何更新会反映在 output.xslx 中,但我将创建一个名为 df_dict 的字典,可以容纳 DataFrames 并根据它们应该写入的工作表进行更新。我相信您可以根据自己的需求调整并使用任何数据结构!
df1 = pd.DataFrame(data = {'A': ['a', 'b', 'c'], 'B': ['g','h','i']})
df2 = pd.DataFrame(data = {'C': ['o', 'p', 'q'], 'D': ['u','v','w']})

df_dict = {'Sheet_1': df1, 'Sheet_2': df2}

with pd.ExcelWriter('output.xlsx') as writer:
    for sheetname, dfname in df_dict.items():
        dfname.to_excel(writer, sheet_name = sheetname)

# Updated data is put in DataFrames
df3 = pd.DataFrame(data = {'A': ['a', 'b', 'c', 'd', 'e', 'f'], 'B': ['g', 'h', 'i', 'j', 'k', 'l']})
df4 = pd.DataFrame(data = {'C': ['o', 'p', 'q', 'r', 's', 't'], 'D': ['u', 'v', 'w', 'x', 'y', 'z']})

# df_dict is updated with the new DataFrames
df_dict = {`Sheet_1`: df3, 'Sheet_2': df4}

# This block now uses the name of the sheet from the workbook itself to get the updated data.
# You could also just run the same block as above and it would work.
with pd.ExcelWriter('output.xlsx', mode = 'a', if_sheet_exists = 'overlay') as writer:
    for sheet in writer.sheets:
        df_dict[sheet].to_excel(writer, sheet_name = sheet)

我只有一个名为“Sheet1”的工作表,并试图向其添加数据。稍后,我将使用pandas 1.5.0版本并尝试您的代码,然后通知您。关于close(),我不知道,也许当文件上的vba按钮移动时,有时会出现“Excel文件损坏”的情况。我会尝试并告诉你。谢谢,如果您需要根据我的评论编辑您的代码,可以这样做,因为稍后我会多次阅读以进入。 - xlmaster
关闭()后,我的Excel文件似乎停用了宏代码。在运行脚本后,我无法运行它。 - xlmaster
你确定使用“从ExcelWriter文档中,.save()已被弃用,应该使用.close()代替。”会损坏xlsm文件吗? - xlmaster
这就是文档中所说的,所以我认为应该是这样的。也许它仍然有效。如果您按照我的答案所做的那样设置,您不需要保存或关闭,因为文件在退出上下文管理器时会自动执行此操作。您还在尝试以不同的方式完成吗? - Andrew
1
ExcelWriter文档中,你可以通过engine_kwargs参数向引擎传递参数。当使用openpyxl作为引擎时,ExcelWriter使用openpyxl.reader.excel.load_workbook方法。从这些文档中得知,keep_vba是一个参数,所以在你的pd.ExcelWriter()参数中添加engine_kwargs = {keep_vba: True}(同时确保你有engine = 'openpyxl'),它应该就可以工作了。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接