简体   繁体   English

如何使用 openpyxl 将工作表从一个工作簿复制到另一个工作簿?

[英]How to copy worksheet from one workbook to another one using openpyxl?

I have a large amount of EXCEL files (ie 200) I would like to copy one specific worksheet from one workbook to another one.我有大量 EXCEL 个文件(即 200 个)我想将一个特定的工作表从一个工作簿复制到另一个工作簿。 I have done some investigations and I couldn't find a way of doing it with Openpyxl我做了一些调查,但找不到使用 Openpyxl 的方法

This is the code I have developed so far这是我到目前为止开发的代码

def copy_sheet_to_different_EXCEL(path_EXCEL_read,Sheet_name_to_copy,path_EXCEL_Save,Sheet_new_name):
''' Function used to copy one EXCEL sheet into another file.
    
    def path_EXCEL_read,Sheet_name_to_copy,path_EXCEL_Save,Sheet_new_name
    
Input data:
    1.) path_EXCEL_read: the location of the EXCEL file along with the name where the information is going to be saved
    2.) Sheet_name_to_copy= The name of the EXCEL sheet to copy
    3.) path_EXCEL_Save: The path of the EXCEL file where the sheet is going to be copied
    3.) Sheet_new_name: The name of the new EXCEL sheet
    
Output data:
    1.) Status= If 0, everything went OK. If 1, one error occurred.

Version History:
1.0 (2017-02-20): Initial version.

'''
status=0

if(path_EXCEL_read.endswith('.xls')==1): 
    print('ERROR - EXCEL xls file format is not supported by openpyxl. Please, convert the file to an XLSX format')
    status=1
    return status
    
try:
   wb = openpyxl.load_workbook(path_EXCEL_read,read_only=True)
except:
    print('ERROR - EXCEL file does not exist in the following location:\n  {0}'.format(path_EXCEL_read))
    status=1
    return status

Sheet_names=wb.get_sheet_names()    # We copare against the sheet name we would like to cpy

if ((Sheet_name_to_copy in Sheet_names)==0):
    print('ERROR - EXCEL sheet does not exist'.format(Sheet_name_to_copy))
    status=1
    return status   

# We checking if the destination file exists

if (os.path.exists(path_EXCEL_Save)==1):
    #If true, file exist so we open it
    
    if(path_EXCEL_Save.endswith('.xls')==1): 
        print('ERROR - Destination EXCEL xls file format is not supported by openpyxl. Please, convert the file to an XLSX format')
        status=1
    return status
    
    try:
        wdestiny = openpyxl.load_workbook(path_EXCEL_Save)
    except:
        print('ERROR - Destination EXCEL file does not exist in the following location:\n  {0}'.format(path_EXCEL_read))
        status=1
    return status

    #we check if the destination sheet exists. If so, we will delete it
    
    destination_list_sheets = wdestiny.get_sheet_names()
    
    if((Sheet_new_name in destination_list_sheets) ==True):
        print('WARNING - Sheet "{0}" exists in: {1}. It will be deleted!'.format(Sheet_new_name,path_EXCEL_Save))
        wdestiny.remove_sheet(Sheet_new_name) 

else:
    wdestiny=openpyxl.Workbook()
# We copy the Excel sheet
    
try:
    sheet_to_copy = wb.get_sheet_by_name(Sheet_name_to_copy) 
    target = wdestiny.copy_worksheet(sheet_to_copy)
    target.title=Sheet_new_name
except:
    print('ERROR - Could not copy the EXCEL sheet. Check the file')
    status=1
    return status

try:
    wdestiny.save(path_EXCEL_Save)
except:
    print('ERROR - Could not save the EXCEL sheet. Check the file permissions')
    status=1
    return status

#Program finishes
return status

You cannot use copy_worksheet() to copy between workbooks because it depends on global constants that may vary between workbooks.您不能使用copy_worksheet()在工作簿之间进行复制,因为它取决于可能因工作簿而异的全局常量。 The only safe and reliable way to proceed is to go row-by-row and cell-by-cell.唯一安全可靠的方法是逐行和逐个单元地进行。

You might want to read the discussions about this feature您可能想阅读有关此功能讨论

I had a similar requirement to collate data from multiple workbooks into one workbook.我有一个类似的要求,将多个工作簿中的数据整理到一个工作簿中。 As there are no inbuilt methods available in openpyxl.由于 openpyxl 中没有可用的内置方法。

I created the below script to do the job for me.我创建了以下脚本来为我完成这项工作。

Note: In my usecase all worbooks contain data in same format.注意:在我的用例中,所有工作簿都包含相同格式的数据。

from openpyxl import load_workbook
import os


# The below method is used to read data from an active worksheet and store it in memory.
def reader(file):
    global path
    abs_file = os.path.join(path, file)
    wb_sheet = load_workbook(abs_file).active
    rows = []
    # min_row is set to 2, to ignore the first row which contains the headers
    for row in wb_sheet.iter_rows(min_row=2):
        row_data = []
        for cell in row:
            row_data.append(cell.value)
        # custom column data I am adding, not needed for typical use cases
        row_data.append(file[17:-6])
        # Creating a list of lists, where each list contain a typical row's data
        rows.append(row_data)
    return rows


if __name__ == '__main__':
    # Folder in which my source excel sheets are present
    path = r'C:\Users\tom\Desktop\Qt'
    # To get the list of excel files
    files = os.listdir(path)
    for file in files:
        rows = reader(file)
        # below mentioned file name should be already created
        book = load_workbook('new.xlsx')
        sheet = book.active
        for row in rows:
            sheet.append(row)
        book.save('new.xlsx')

I've just found this question.我刚刚发现了这个问题。 A good workaround, as mentioned here , could consists in modifying the original wb in memory and then saving it with another name.一个很好的解决方法,正如这里提到的,可以包括修改内存中的原始wb ,然后用另一个名称保存它。 For example:例如:

import openpyxl

# your starting wb with 2 Sheets: Sheet1 and Sheet2
wb = openpyxl.load_workbook('old.xlsx')

sheets = wb.sheetnames # ['Sheet1', 'Sheet2']

for s in sheets:

    if s != 'Sheet2':
        sheet_name = wb.get_sheet_by_name(s)
        wb.remove_sheet(sheet_name)

# your final wb with just Sheet1
wb.save('new.xlsx')

My workaround goes like this:我的解决方法是这样的:

You have a template file let's say it's "template.xlsx".您有一个模板文件,假设它是“template.xlsx”。 You open it, make changes to it as needed, save it as a new file, close the file.您打开它,根据需要对其进行更改,将其另存为新文件,然后关闭该文件。 Repeat as needed.根据需要重复。 Just make sure to keep a copy of the original template while testing/messing around.只需确保在测试/乱搞时保留原始模板的副本。

I had the same problem.我有同样的问题。 For me style, format, and layout were very important.对我来说,风格、格式和布局非常重要。 Moreover, I did not want to copy formulas but only the value (of the formulas).此外,我不想复制公式,而只想复制(公式的)值。 After a lot of trail, error, and stackoverflow I came up with the following functions.经过大量的跟踪、错误和stackoverflow,我想出了以下函数。 It may look a bit intimidating but the code copies a sheet from one Excel file to another (possibly existing file) while preserving:它可能看起来有点吓人,但代码将工作表从一个 Excel 文件复制到另一个(可能存在的文件),同时保留:

  1. font and color of text文字的字体和颜色
  2. filled color of cells单元格填充颜色
  3. merged cells合并单元格
  4. comment and hyperlinks评论和超链接
  5. format of the cell value单元格值的格式
  6. the width of every row and column每行和每列的宽度
  7. whether or not row and column are hidden行和列是否隐藏
  8. frozen rows冻结行

It is useful when you want to gather sheets from many workbooks and bind them into one workbook.当您想从许多工作簿中收集工作表并将它们绑定到一个工作簿中时,它很有用。 I copied most attributes but there might be a few more.我复制了大部分属性,但可能还有一些。 In that case you can use this script as a jumping off point to add more.在这种情况下,您可以使用此脚本作为起点来添加更多内容。

###############
## Copy a sheet with style, format, layout, ect. from one Excel file to another Excel file
## Please add the ..path\\+\\file..  and  ..sheet_name.. according to your desire.

import openpyxl
from copy import copy

def copy_sheet(source_sheet, target_sheet):
    copy_cells(source_sheet, target_sheet)  # copy all the cel values and styles
    copy_sheet_attributes(source_sheet, target_sheet)


def copy_sheet_attributes(source_sheet, target_sheet):
    target_sheet.sheet_format = copy(source_sheet.sheet_format)
    target_sheet.sheet_properties = copy(source_sheet.sheet_properties)
    target_sheet.merged_cells = copy(source_sheet.merged_cells)
    target_sheet.page_margins = copy(source_sheet.page_margins)
    target_sheet.freeze_panes = copy(source_sheet.freeze_panes)

    # set row dimensions
    # So you cannot copy the row_dimensions attribute. Does not work (because of meta data in the attribute I think). So we copy every row's row_dimensions. That seems to work.
    for rn in range(len(source_sheet.row_dimensions)):
        target_sheet.row_dimensions[rn] = copy(source_sheet.row_dimensions[rn])

    if source_sheet.sheet_format.defaultColWidth is None:
        print('Unable to copy default column wide')
    else:
        target_sheet.sheet_format.defaultColWidth = copy(source_sheet.sheet_format.defaultColWidth)

    # set specific column width and hidden property
    # we cannot copy the entire column_dimensions attribute so we copy selected attributes
    for key, value in source_sheet.column_dimensions.items():
        target_sheet.column_dimensions[key].min = copy(source_sheet.column_dimensions[key].min)   # Excel actually groups multiple columns under 1 key. Use the min max attribute to also group the columns in the targetSheet
        target_sheet.column_dimensions[key].max = copy(source_sheet.column_dimensions[key].max)  # https://stackoverflow.com/questions/36417278/openpyxl-can-not-read-consecutive-hidden-columns discussed the issue. Note that this is also the case for the width, not onl;y the hidden property
        target_sheet.column_dimensions[key].width = copy(source_sheet.column_dimensions[key].width) # set width for every column
        target_sheet.column_dimensions[key].hidden = copy(source_sheet.column_dimensions[key].hidden)


def copy_cells(source_sheet, target_sheet):
    for (row, col), source_cell in source_sheet._cells.items():
        target_cell = target_sheet.cell(column=col, row=row)

        target_cell._value = source_cell._value
        target_cell.data_type = source_cell.data_type

        if source_cell.has_style:
            target_cell.font = copy(source_cell.font)
            target_cell.border = copy(source_cell.border)
            target_cell.fill = copy(source_cell.fill)
            target_cell.number_format = copy(source_cell.number_format)
            target_cell.protection = copy(source_cell.protection)
            target_cell.alignment = copy(source_cell.alignment)

        if source_cell.hyperlink:
            target_cell._hyperlink = copy(source_cell.hyperlink)

        if source_cell.comment:
            target_cell.comment = copy(source_cell.comment)


wb_target = openpyxl.Workbook()
target_sheet = wb_target.create_sheet(..sheet_name..)

wb_source = openpyxl.load_workbook(..path\\+\\file_name.., data_only=True)
source_sheet = wb_source[..sheet_name..]

copy_sheet(source_sheet, target_sheet)

if 'Sheet' in wb_target.sheetnames:  # remove default sheet
    wb_target.remove(wb_target['Sheet'])

wb_target.save('out.xlsx')

I would using openpyxl.worksheet.copier.WorksheetCopy我会使用 openpyxl.worksheet.copier.WorksheetCopy

import pandas as pd
import openpyxl
from openpyxl.worksheet.copier import WorksheetCopy
   
wb1 = openpyxl.load_workbook("file1.xlsx",read_only=True)
ws1 = wb1.worksheets[-1]   # last worksheet
wb2 = openpyxl.load_workbook("file2.xlsx")
ws2 = wb2.create_worksheet('new')
copier = WorkSheetCopy(ws1, ws2)
copier.copy_sheet()
writer = pd.ExcelWriter("output.xlsx", engine="openpyxl")
writer.book = wb2
writer.save()


    

我使用的解决方法是将当前工作表保存为 Pandas 数据框并将其加载到您需要的 excel 工作簿中

For speed I am using data_only and read_only attributes when opening my workbooks.为了速度,我在打开工作簿时使用data_onlyread_only属性。 Also iter_rows() is really fast, too. iter_rows()也非常快。

@Oscar's excellent answer needs some changes to support ReadOnlyWorksheet and EmptyCell @Oscar 的出色答案需要进行一些更改以支持 ReadOnlyWorksheet 和 EmptyCell

# Copy a sheet with style, format, layout, ect. from one Excel file to another Excel file
# Please add the ..path\\+\\file..  and  ..sheet_name.. according to your desire.
import openpyxl
from copy import copy


def copy_sheet(source_sheet, target_sheet):
    copy_cells(source_sheet, target_sheet)  # copy all the cel values and styles
    copy_sheet_attributes(source_sheet, target_sheet)


def copy_sheet_attributes(source_sheet, target_sheet):
    if isinstance(source_sheet, openpyxl.worksheet._read_only.ReadOnlyWorksheet):
        return
    target_sheet.sheet_format = copy(source_sheet.sheet_format)
    target_sheet.sheet_properties = copy(source_sheet.sheet_properties)
    target_sheet.merged_cells = copy(source_sheet.merged_cells)
    target_sheet.page_margins = copy(source_sheet.page_margins)
    target_sheet.freeze_panes = copy(source_sheet.freeze_panes)

    # set row dimensions
    # So you cannot copy the row_dimensions attribute. Does not work (because of meta data in the attribute I think). So we copy every row's row_dimensions. That seems to work.
    for rn in range(len(source_sheet.row_dimensions)):
        target_sheet.row_dimensions[rn] = copy(source_sheet.row_dimensions[rn])

    if source_sheet.sheet_format.defaultColWidth is None:
        print('Unable to copy default column wide')
    else:
        target_sheet.sheet_format.defaultColWidth = copy(source_sheet.sheet_format.defaultColWidth)

    # set specific column width and hidden property
    # we cannot copy the entire column_dimensions attribute so we copy selected attributes
    for key, value in source_sheet.column_dimensions.items():
        target_sheet.column_dimensions[key].min = copy(source_sheet.column_dimensions[key].min)   # Excel actually groups multiple columns under 1 key. Use the min max attribute to also group the columns in the targetSheet
        target_sheet.column_dimensions[key].max = copy(source_sheet.column_dimensions[key].max)  # https://stackoverflow.com/questions/36417278/openpyxl-can-not-read-consecutive-hidden-columns discussed the issue. Note that this is also the case for the width, not onl;y the hidden property
        target_sheet.column_dimensions[key].width = copy(source_sheet.column_dimensions[key].width) # set width for every column
        target_sheet.column_dimensions[key].hidden = copy(source_sheet.column_dimensions[key].hidden)


def copy_cells(source_sheet, target_sheet):
    for r, row in enumerate(source_sheet.iter_rows()):
        for c, cell in enumerate(row):
            source_cell = cell
            if isinstance(source_cell, openpyxl.cell.read_only.EmptyCell):
                continue
            target_cell = target_sheet.cell(column=c+1, row=r+1)

            target_cell._value = source_cell._value
            target_cell.data_type = source_cell.data_type

            if source_cell.has_style:
                target_cell.font = copy(source_cell.font)
                target_cell.border = copy(source_cell.border)
                target_cell.fill = copy(source_cell.fill)
                target_cell.number_format = copy(source_cell.number_format)
                target_cell.protection = copy(source_cell.protection)
                target_cell.alignment = copy(source_cell.alignment)

            if not isinstance(source_cell, openpyxl.cell.ReadOnlyCell) and source_cell.hyperlink:
                target_cell._hyperlink = copy(source_cell.hyperlink)

            if not isinstance(source_cell, openpyxl.cell.ReadOnlyCell) and source_cell.comment:
                target_cell.comment = copy(source_cell.comment)

With a usage something like使用类似

    wb = Workbook()
    
    wb_source = load_workbook(filename, data_only=True, read_only=True)
    for sheetname in wb_source.sheetnames:
        source_sheet = wb_source[sheetname]
        ws = wb.create_sheet("Orig_" + sheetname)
        copy_sheet(source_sheet, ws)

    wb.save(new_filename)

i found a way playing around with it我找到了一种玩弄它的方法

import openpyxl

xl1 = openpyxl.load_workbook('workbook1.xlsx')
# sheet you want to copy
s = openpyxl.load_workbook('workbook2.xlsx').active
s._parent = xl1
xl1._add_sheet(s)
xl1.save('some_path/name.xlsx')

查看此代码,该代码简化了从一个电子表格复制和粘贴到另一个电子表格的过程: https : //github.com/dabomb1004/Excel-CopyPaste

It actually can be done in a very simple way !它实际上可以用非常简单的方式完成! It just need 3 steps:它只需要3个步骤:

  1. Open a file using load_workbook使用 load_workbook 打开一个文件

    wb = load_workbook('File_1.xlsx') wb = load_workbook('File_1.xlsx')

  2. Select a sheet you want to copy Select 一张你要复印的表

    ws = wb.active ws = wb.active

  3. use name of the new file to save the file使用新文件的名称来保存文件

    wb.save('New_file.xlsx') wb.save('New_file.xlsx')

This code will save sheet of first file (File_1.xlsx) to the secound file (New_file.xlsx).此代码会将第一个文件 (File_1.xlsx) 的工作表保存到第二个文件 (New_file.xlsx)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 想要使用 openpyxl 将工作表从一个工作簿添加到另一个工作簿 - want to add worksheet from one workbook in to another workbook using openpyxl Python/openpyxl - 有没有办法将工作表从一个工作簿复制到另一个具有所有属性的工作簿(精确副本) - Python/openpyxl - Is there a way to copy a worksheet from one workbook to another with all properties (exact copy) 尝试使用 OPENPYXL 将一系列单元格从一个工作簿复制到另一个工作簿 - Trying to copy a range of cells from one workbook to another using OPENPYXL 使用openpyxl将单元格值列从一个工作簿复制到另一个工作簿 - Copy column of cell values from one workbook to another with openpyxl 保存时使用openpyxl从一个工作簿复制到另一个工作簿会导致错误 - Using openpyxl to copy from one workbook to another results in error when saving 使用 openpyxl 将工作表(数据+样式)从工作簿复制到 Python 中的另一个 - Copy a worksheet (data+style) from a workbook to another in Python using openpyxl 使用 Openpyxl 将特定列从一个工作簿复制到另一个工作簿 - Copying Specific Column from One Workbook to Another using Openpyxl 使用Openpyxl将数据从一个工作簿移动到另一个工作簿 - Moving Data From One Workbook To Another With Openpyxl 将工作表从一个工作簿复制到另一个工作簿 - Copying a worksheet from one workbook to another 使用openpyxl将公式从一个单元格复制到另一个单元格 - Copy formula from one cell to another using openpyxl
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM