excel写入类——实现合并单元格,pandas,xlwt

import xlwt
import pandas as pd

class Excel_style:
    """excel表格样式类"""
    def __init__(self, font_heigh):
        self.font_heigh = font_heigh  # 字体大小:磅

    @property
    def cell_style(self):
        """表格内容样式"""
        style = xlwt.XFStyle()  # 创建一个样式对象,初始化样式
        al = xlwt.Alignment()
        al.horz = 0x02  # 设置水平居中
        al.vert = 0x01  # 设置垂直居中
        style.alignment = al
        font=xlwt.Font()
        font.height = 20*self.font_heigh
        style.font=font
        return style

    @property
    def title_style(self):
        """表格标题样式"""
        style = xlwt.XFStyle()  # 创建一个样式对象,初始化样式
        al = xlwt.Alignment()
        al.horz = 0x02  # 设置水平居中
        al.vert = 0x01  # 设置垂直居中
        style.alignment = al
        font=xlwt.Font()
        font.height = 20*self.font_heigh
        font.bold = True
        style.font=font
        return style

    def fit_width(self,max_width,value):
        """调整自适应列宽"""
        width = len(str(value).encode('utf-8'))*256
        if width < 2960:
            max_width = 2960
        if width > max_
            max_width = width
        return int(max_width + max_width * 1/10)

    @property
    def fit_heigh(self):
        """调整自适应行高"""
        heigh_style = xlwt.easyxf('font:height %s;'%(20 * (self.font_heigh+4)))
        return heigh_style

class Excel_writer:
    """excel表格写入类"""
    def __init__(self, excel_path, df):
        self.excel_path = excel_path
        self.df = (df.drop(columns='index') if 'index' in df.columns else df)
        self.cols = list(self.df.columns.values)  # 行索引值列表
        self.index_len = self.df.index.size  # 索引长度
        self.column_number = {col: idx for idx, col in enumerate(self.cols)}  # 得到 行索引值:索引
        self.excel = xlwt.Workbook(excel_path)
        self.worksheet = self.excel.add_sheet('sheet1')
        self.style_obj = Excel_style(10)
    
    def write_to_exel(self):
        """pandas 写入 excel 表格"""
        self.df.to_excel(self.excel_path, index=False)

    def _get_group_idx(self, key_col):
        """合并单元格的索引数据"""
        """
        return [[1,2],[3,4]]
        """
        groups = self.df.groupby(key_col)
        idxs = [[groups.get_group(i).index.min() + 1, groups.get_group(i).index.max() + 1] for i in groups.size().index]
        return idxs, len(idxs)        
    
    def _fit_value(self,value):
        """调整 pandas 值,适应 excel 表格"""
        if isinstance(value,str):
            return str(value)
        if isinstance(value,pd._libs.tslibs.timestamps.Timestamp):
            value = str(value)
            if '.' in value:
                value = value.split('.')[0]
            return value
        return int(value)
        
    
    def write_merged_by_col_to_excel(self, key_col, merged_cols):
        """根据 key列,合并设定的单元格,写入 excel 表格,有样式"""
        if key_col not in self.cols:  # 校验key_cols中各元素 是否都包含与对象的列
            return
        if not all([v in self.cols for i, v in enumerate(merged_cols)]):  # 校验merge_cols中各元素 是否都包含与对象的列
            return
        self.write_head()
        self.write_merge_body(key_col,merged_cols)
        self.save()

    def write_style_to_excel(self):
        """写入excel,有样式"""
        self.write_head()
        self.write_body()
        self.save()

    def write_head(self):
        """写入标题,有样式"""
        for col_value, i in self.column_number.items():  # 写表头
            heigh_style = self.style_obj.fit_heigh
            self.worksheet.row(0).set_style(heigh_style)
            self.worksheet.write(0, i, col_value, self.style_obj.title_style)

    def write_body(self):
        """写入内容,有样式"""
        for col_value, idx in self.column_number.items():
            max_width = 2960
            for i in range(self.index_len):
                value = self.df.at[i, col_value]
                if pd.isna(value):
                    value = ''
                max_width = self.style_obj.fit_width(max_width,value)
                self.worksheet.col(idx).width = max_width
                heigh_style = self.style_obj.fit_heigh
                self.worksheet.row(i + 1).set_style(heigh_style)
                self.worksheet.write(i + 1, int(idx), self._fit_value(value),self.style_obj.cell_style)
    
    def write_merge_body(self, key_col, merged_cols):
        """"写入内容,合并单元格,有样式"""
         for col_value, idx in self.column_number.items():
            max_width = 2960
            if col_value not in merged_cols:
                for i in range(self.index_len):
                    value = self.df.at[i, col_value]
                    if pd.isna(value):
                        value = ''
                    max_width = self.style_obj.fit_width(max_width,value)
                    self.worksheet.col(idx).width = max_width
                    heigh_style = self.style_obj.fit_heigh
                    self.worksheet.row(i + 1).set_style(heigh_style)
                    self.worksheet.write(i + 1, int(idx), self._fit_value(value),self.style_obj.cell_style)
            else:
                idxs, _ = self._get_group_idx(key_col)
                for j in idxs:
                    value = self.df.at[j[0] - 1, col_value]
                    if pd.isna(value):
                        value = ''
                    max_width = self.style_obj.fit_width(max_width,value)
                    self.worksheet.col(idx).width = max_width
                    heigh_style = self.style_obj.fit_heigh
                    self.worksheet.row(int(j[0])).set_style(heigh_style)
                    self.worksheet.write_merge(int(j[0]), int(j[1]), int(idx), int(idx), self._fit_value(value),self.style_obj.cell_style)
    
    def save(self):
        """保存 excel 表格"""
        self.excel.save(self.excel_path)


if __name__ == '__main__':
    te = {'A': ['aaa', 'aaa', 'aaa', 'aaa', 'CCC', 'CCC'], 'B': ['bbbb', 'aaa', 'aaa', 'aaa', 'aaa', 'aaa'], 'C': ['aaa', 'aaa', 'aaa', 'aaa', 'aaa', 'aaa']}
    t_f = pd.DataFrame(te)
    DF = Excel_writer(r'D:EL_giteeel_appsrcapp_vi00_1.xls', t_f)
    # DF.merged_by_col_to_excel('A',['A', 'B', 'C'])
    DF.write_style_to_excel()

参考:https://blog.csdn.net/cakecc2008/article/details/59203980

原文地址:https://www.cnblogs.com/pythonwl/p/15103020.html