在Python中将一个Excel表格从一个工作表复制到另一个工作表

3
我想做的就是在Python中从一个Excel工作簿复制工作表到另一个Excel工作簿。
我想保留所有格式(彩色单元格,表格等)。
我有许多Excel文件,我想将它们的第一张工作表复制到一个工作簿中。如果对任何个人工作簿进行更改,我还想能够更新主工作簿。
这是一个代码块,每隔几个小时运行一次,并更新主要电子表格。
我尝试了pandas,但它不保留格式和表格。
我也尝试过openpyxl,但没有成功。
我认为下面的xlwings代码会起作用:
import xlwings as xw

wb = xw.Book('individual_files\\file1.xlsx')
sht = wb.sheets[0]
new_wb = xw.Book('Master Spreadsheet.xlsx')
new_wb.sheets["Sheet1"] = sht

但是我只得到了错误:

----> 4 new_wb.sheets["Sheet1"] = sht

AttributeError: __setitem__

上面的 "file1.xlsx" 是一个Excel文件示例。

"Master Spreadsheet.xlsx" 是我带有所有个人文件的主要电子表格。


你在这里做的是将当前工作簿中的一个工作表赋值为另一个工作簿中的一个工作表。我预计这会引发错误,因为这不是复制工作表的方法。这个回答有帮助吗?https://dev59.com/8VcO5IYBdhLWcg3wWgQ0 - David Zemens
xlwings 是您唯一的选择吗? - Chillie
@Chillie 不是的,事实上,我宁愿不使用它! - Pythonner12
你可能需要查看这个(解决方案2)。你可以使用pip获取pywin32包。但请注意,如果出现异常,你可能需要使用任务管理器终止Excel进程。 - Chillie
3个回答

1
最终我做了这个:


def copyExcelSheet(sheetName):

read_from = load_workbook(item)
#open(destination, 'wb').write(open(source, 'rb').read())
read_sheet = read_from.active
write_to = load_workbook("Master file.xlsx")
write_sheet = write_to[sheetName]

for row in read_sheet.rows:
    for cell in row:
        new_cell = write_sheet.cell(row=cell.row, column=cell.column,
                value= cell.value)
        write_sheet.column_dimensions[get_column_letter(cell.column)].width = read_sheet.column_dimensions[get_column_letter(cell.column)].width
        if cell.has_style:
            new_cell.font = copy(cell.font)
            new_cell.border = copy(cell.border)
            new_cell.fill = copy(cell.fill)
            new_cell.number_format = copy(cell.number_format)
            new_cell.protection = copy(cell.protection)
            new_cell.alignment = copy(cell.alignment)

write_sheet.merge_cells('C8:G8')
write_sheet.merge_cells('K8:P8')
write_sheet.merge_cells('R8:S8')

write_sheet.add_table(newTable("table1","C10:G76","TableStyleLight8"))
write_sheet.add_table(newTable("table2","K10:P59","TableStyleLight9"))

write_to.save('Master file.xlsx')
read_from.close

使用此代码来检查表格是否已经存在:

#checks if sheet already exists and updates sheet if it does.
def checkExists(sheetName):
    book = load_workbook("Master file.xlsx")   # open an Excel file and return a workbook

    if sheetName in book.sheetnames:
        print ("Removing sheet",sheetName)
        del book[sheetName]
    else:
        print ("No sheet ",sheetName," found, will create sheet")

    book.create_sheet(sheetName)
    book.save('Master file.xlsx')

使用此功能创建新表格:
def newTable(tableName,ref,styleName):
    tableName = tableName + ''.join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k=15))
    tab = Table(displayName=tableName, ref=ref)
    # Add a default style with striped rows and banded columns
    tab.tableStyleInfo = TableStyleInfo(name=styleName, showFirstColumn=False,showLastColumn=False, showRowStripes=True, showColumnStripes=True)
    return tab

这个可行,谢谢!我已经删除了 column_dimension 行,不知道 get_column_letter 是在哪里定义的。还得从 copy 中导入 copy - sudo_dudo

0

这可以直接使用pywin32完成。需要提供Before或After参数(请参阅API文档),并且参数需要是一个工作表<object>,而不仅仅是工作表名称或索引值。因此,例如,要将其添加到现有工作簿的末尾:

def copy_sheet_within_excel_file(excel_filename, sheet_name_or_number_to_copy):
    excel_app = win32com_client.gencache.EnsureDispatch('Excel.Application')
    wb = excel_app.Workbooks.Open(excel_filename)
    wb.Worksheets[sheet_name_or_number_to_copy].Copy(After=wb.Worksheets[wb.Worksheets.Count])
    new_ws = wb.ActiveSheet
    return new_ws

由于我的大部分代码在最终用户的计算机上运行,我不喜欢做出假设,即Excel是否已打开,因此我的代码会确定Excel是否已经打开(请参见GetActiveObject),如下所示:

    try:
        excel_app = win32com_client.GetActiveObject('Excel.Application')
    except com_error:
        excel_app = win32com_client.gencache.EnsureDispatch('Excel.Application')

然后我还会检查工作簿是否已经加载(参见Workbook.FullName)。通过迭代Application.Workbooks来测试FullName,以查看文件是否已经打开。如果是,则将该wb作为您的wb句柄。

您可能会发现直接从pywin32挖掘可用的Excel API很有帮助:

def show_python_interface_modules():
        os.startfile(os.path.dirname(win32com_client.gencache.GetModuleForProgID('Excel.Application').__file__))

0

改编自 这个方案,但请注意在我的(有限的)测试中(以及在其他问答中观察到),它不支持 Copy 方法的After参数,只支持Before。如果您尝试使用After,它会创建一个新的工作簿。

import xlwings as xw

wb = xw.Book('individual_files\\file1.xlsx')
sht = wb.sheets[0]
new_wb = xw.Book('Master Spreadsheet.xlsx')
# copy this sheet into the new_wb *before* Sheet1:
sht.api.Copy(Before=new_wb.sheets['Sheet1'].api)
# now, remove Sheet1 from new_wb
new_wb.sheets['Sheet1'].delete()

1
After参数已经实现,只是写法有点不同。您只需要在After参数之前使用None即可。例如:sht.api.Copy(None, After=wb.sheets[-1].api)。请参见此处 - mouwsy

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