You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Openpyxl追加Pandas DataFrame至Excel工作表时,文件保存后数据未生效的问题排查

使用Openpyxl追加Pandas DataFrame至Excel工作表时,文件保存后数据未生效的问题排查

我想要把Pandas DataFrame中的数据追加到现有的Excel工作表和Excel表格(ListObject)中,目前使用openpyxl来实现这个功能。

我现在正在编写写入工作表的代码,具体如下:

def _append_to_excel_sheet(self
                        , data_to_write: pd.DataFrame
                        , excel_file: str
                        , sheet_name: str
                        , **kwargs
                        ) -> bool:
    
    try:
        if Path(excel_file).exists():
            # Load existing workbook
            self.logger.debug(f"Appending {len(data_to_write)} rows to sheet {sheet_name} in {excel_file}")
            with open (excel_file, "rb") as f:
                wb = load_workbook(f
                    , read_only=False
                    , keep_vba=True
                    , data_only=False
                    , keep_links=True
                    , rich_text=True
                    )
            self.logger.debug(wb.sheetnames)
            
            ws = wb[sheet_name] if sheet_name in wb.sheetnames else wb.create_sheet(sheet_name)
            
            # Find last row with data
            last_row = ws.max_row
            
            # Write new data
            for idx, row in enumerate(data_to_write.values):
                self.logger.debug(f"Appending row: {row} to row: {last_row + idx + 1}")
                for col_idx, value in enumerate(row, 1):
                    ws.cell(row=last_row + idx + 1, column=col_idx, value=value)
            
            self.logger.debug(f"New range: {ws.cell(row=last_row + 1, column=1).coordinate}:{ws.cell(row=last_row + len(data_to_write), column=len(data_to_write.columns)).coordinate}")
            self.logger.debug(f"Saving to file {excel_file}")
            wb.save(excel_file)
            
        else:
            # Create new file if it doesn't exist
            self.logger.debug(f"Creating new file {excel_file} and writing {len(data_to_write)} rows to sheet {sheet_name}")
            with pd.ExcelWriter(excel_file, engine='openpyxl') as writer:
                data_to_write.to_excel(
                    writer,
                    sheet_name=sheet_name,
                    index=False
                )
                
    except Exception as e:
        self.logger.error(f"Failed to write to Excel: {str(e)}")
        raise

    finally:
        wb.close()

当我运行这段代码时,logger对象能正常执行到self.logger.debug(f"Saving to file {excel_file}")这一行,没有抛出任何异常。在我的测试中,也从未触发异常分支的self.logger.error(f"Failed to write to Excel: {str(e)}")代码。

我查阅了openpyxl的官方文档以及Stack Overflow上的多个类似问题,但始终没找到代码中的问题。传入函数的文件路径是绝对路径。

我知道可以直接用Pandas追加DataFrame到现有工作表,这本来是理想的解决方案,但我同时也需要对Excel表格(ListObject)实现同样的追加功能。

请问:

  • 有没有办法开启openpyxl的verbose模式,查看它后台的具体操作?
  • 是不是我忽略了同名文件保存的某些限制条件?
  • 如果我无法修复当前问题,还有哪些替代方案可以考虑?

编辑

补充一下我调用这段代码的上下文:这个函数是ExcelOutputHandler类的一个方法,我在Unittest.TestCase中这样调用它:

from datetime import datetime
from pathlib import Path
import sys
import unittest
from src.core.types import City # this is a NamedTuple
from src.output_handler import ExcelOutputHandler


import logging

class test_output_handler(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        cls.logger = logging.getLogger()
        cls.logger.setLevel(logging.DEBUG)
        cls.logger.addHandler(logging.StreamHandler(sys.stdout))
        cls.test_dir = Path(__file__).parent

        cls.xl_testfile = cls.test_dir / f"./output_history/{datetime.now().strftime("%Y-%m-%d %H-%M-%S")}.xlsx"

        with open(cls.test_dir / "./test_worksheet.xlsx", "rb") as template_testfile:
            with open(cls.xl_testfile, "wb+") as testfile:
                testfile.write(template_testfile.read())


    @classmethod
    def tearDownClass(cls) -> None:
        pass


    def setUp(self) -> None:
        
        pass


    def tearDown(self) -> None:
        pass


    def test_write_to_sheet_overlay(self) -> None:
        handler = ExcelOutputHandler(self.logger)

        data = [
            City('London', 'UK', 'EU', 'Rainy', 50, 'S', 5)
            , City('Paris', 'FR', 'EU', 'Sunny', 10, 'A', 6)
            , City('Berlin', 'DE', 'EU', 'Cold', 20, 'A', 3)
            , City('Brussels', 'BE', 'EU', 'Cold', 10, 'B', 6)
            , City('Lisbon', 'PT', 'EU', 'Sunny', 20, 'S+', 7)
            , City('Oslo', 'NW', 'EU', 'Cold', 10, 'S', 3)
            , City('Vienna', 'AT', 'EU', 'Cold', 10, 'A+', 8)
        ]

        handler._append_to_excel_sheet(data, str(self.xl_testfile), "Sheet2")
        handler._append_to_excel_sheet(data, str(self.xl_testfile), "Sheet2")

        # Verify the results
        import openpyxl
        wb = openpyxl.load_workbook(str(self.xl_testfile))
        ws = wb["Sheet2"]
        
        # Get the number of rows with data (excluding header)
        row_count = sum(1 for row in ws.iter_rows(min_row=2) if any(cell.value for cell in row))
        
        # Assert we have twice the number of data rows
        self.assertEqual(row_count, len(data) * 2, 
                        f"Expected {len(data) * 2} rows but found {row_count}")
        
        wb.close()

在测试中,我期望Excel文件包含14条数据行,但测试总是失败,报错信息为AssertionError: 0 != 14 : Expected 14 rows but found 0。我参考了相关资料,认为初始化xl_testfile的代码会复制test_worksheet文件,然后让测试可以正常访问它。

备注:内容来源于stack exchange,提问作者Pollastre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 03:20:37