一、背景

在实际工作中,有时需要写个定时脚本,每天自动发报表、监控等数据。有时需要在邮件的正文展示表格。
如果使用简单的html语法,例如代码1发邮件(代码在本文最后),则发出的表格如下图:

可以看出表格不太美观且数据杂乱。
基于此需求,开发了美化后的表格,且支持排序、合并单元格等操作。使用代码2可实现下图的表格效果

二、总体思路

相邻单元格中的值如果相同则会自动合并单元格。例如下图中的红框位置:

三、如何使用

以下是代码2中的方法,代码2见文章最后面

3.1 排序

方法:sort_data(data, sortlist)
参数【data】要排序的二维数据
参数【sortlist】排序的标准。data的第一列会按照sortlist[0]的顺序来排序,第二列按照sortlist[1]的顺序来排序。

例如 sortlist=[[‘初一’, ‘初二’], [‘语文’, ‘数学’]],那么 第一列 会按照初一、初二的顺序来排序,第二列 会按照语文、数学的顺序来排序。

3.2 数据转html表格

方法:data_to_html(data, titles, head=None, datacol=0, rowspan=False, colspan=False)
参数【data】数据二维列表
参数【titles】表头二维列表,例如[['年级', '学科']]
参数【head】表格标题,默认为None
参数【datacol】datacol=2表示从第二列开始是统计数据,统计数据不会进行合并,只有第二列之前会合并
参数【rowspan】是否进行垂直合并,默认否
参数【colspan】是否进行水平合并,默认否
3.2.1 常规表格
html1 = data_to_html(data, titles, head)

3.2.2 排序
data = sort_data(data, [sorted_grade, sorted_subject])
html2 = data_to_html(data, titles, head)

3.2.3 垂直合并表格
data = sort_data(data, [sorted_grade, sorted_subject]) #不需要排序时可以去掉这行
html3 = data_to_html(data, titles, head, 2, True, False)

3.2.4 水平合并表格
data = sort_data(data, [sorted_grade, sorted_subject]) #不需要排序时可以去掉这行
html4 = data_to_html(data, titles, head, 2, False, True)

3.2.5 垂直水平合并表格
data = sort_data(data, [sorted_grade, sorted_subject]) #不需要排序时可以去掉这行
html5 = data_to_html(data, titles, head, 2, True, True)

3.2.6 自定义宽度
data = sort_data(data, [sorted_grade, sorted_subject]) #不需要排序时可以去掉这行
html5 = data_to_html(data, titles, head, 2, True, True, [160, 120, 0, 50])
#前四列宽度依次为160 120 80 50,第五列后面的默认80,0也会转化为80

3.2.7 自定义颜色字号
data = sort_data(data, [sorted_grade, sorted_subject]) #不需要排序时可以去掉这行
html7 = data_to_html(data, titles, head, 2, True, True, [], True)

代码1

def data_to_html(data, title):alarm_html = '<table border="1" cellpadding="5"><tr>'for item in title:alarm_html += '<td>%s</td>' % itemalarm_html += '</tr>'for row in data:alarm_html += '<tr>'for item in row:alarm_html += '<td>%s</td>' % itemalarm_html += "</tr>"alarm_html += "</table>"return alarm_htmlif __name__ == '__main__':titles = ['表头1', '表头2', '表头3', '表头4', '表头5']data = [['小学', '语文', 1, 1, 3],['小学', '数学', 1, 5, 1],['小学', '语文', 1, 1, 33],['初中', '数学', 13, 1, 15],['高中', '数学', 1, 1, 1],['小学', '英语', 1, 8, 1],['小学汇总', '小学汇总', 1, 1, 1],['初中', '数学', 13, 1, 15],['小学', '语文', 1, 1, 33],['高中汇总', '高中汇总', 13, 1, 15]]html1 = data_to_html(data, titles)mail_to = '123@qq.com'subject = '邮件主题'msg_txt = html1# mail_to:邮箱 subject:主题 msg_txt:正文send_mail(mail_to, subject, msg_txt)

代码2


def get_sort_list(l_type):if l_type == '年级':return ['小学', '初中', '高中']if l_type == '学科':return ['语文', '数学', '英语', '物理', '化学']def sort_data(data, sortlist):def get_sort_num(sort_dict, item):for k in sort_dict:if k in item:return sort_dict[k]return len(sort_dict)for i in range(len(sortlist) - 1, -1, -1):sort_mode = sortlist[i]sort_dict = {}sort_len = len(sort_mode)for j in range(sort_len):sort_dict[sort_mode[j]] = jdata = sorted(data, key=lambda x: get_sort_num(sort_dict, x[i]))return datadef format_data(data_c):data = copy.deepcopy(data_c)for i in range(len(data)):for j in range(len(data[i])):data[i][j] = [data[i][j], 1, 1, '', '']return datadef rowspan_data(data, datacol):datacol = min(len(data), datacol)last_split = [0, len(data)]  # 前一列的分片,后一列分片要在前一列分片的基础上再分for j in range(datacol):  # 遍历列next_split = [0]for spliti in range(len(last_split) - 1):  # 遍历分片item_num = {}  # 值和出现次数item_list = []  # 值出现顺序,去重for i in range(last_split[spliti], last_split[spliti + 1]):  # 遍历分片下的单元格item = data[i][j][0]  # 单元格的值if item not in item_num:item_list.append(item)item_num[item] = 0item_num[item] = item_num[item] + 1  # 统计出现次数item_in = set()  # 合并单元格rowspan除了第一个外都写0for i in range(last_split[spliti], last_split[spliti + 1]):  # 遍历分片下的单元格item = data[i][j][0]  # 单元格的值if item not in item_in:data[i][j][1] = item_num[item]  # 把出现次数写进去item_in.add(item)else:data[i][j][1] = 0num_list = []  # 分片内值和次数for item in item_list:num_list.append(item_num[item])last_num = next_split[-1]for num in num_list:next_split.append(last_num + num)last_num = next_split[-1]last_split = next_split  # 生成新的分片return datadef colspan_data(data, datacol):datacol = min(len(data[0]), datacol)for i in range(len(data)):item_num = {}  # 值和出现次数item_list = []  # 值出现顺序,去重for j in range(datacol):item = data[i][j][0]if item not in item_num:item_list.append(item)item_num[item] = 0item_num[item] = item_num[item] + 1  # 统计出现次数item_in = set()  # 合并单元格rowspan除了第一个外都写0for j in range(datacol):item = data[i][j][0]  # 单元格的值if item not in item_in:data[i][j][2] = item_num[item]  # 把出现次数写进去item_in.add(item)else:data[i][j][2] = 0return datadef font_data(data, args):'''method:可根据需求对此函数进行修改'''colors = ["#00BB00", "#FF8000", "#FF0000", '#FF00FF']  # 绿、橙、红、紫sizes = ['2', '3', '4']for i in range(len(data)):for j in range(len(data[i])):data[i][j][3] = colors[i % len(colors)]data[i][j][4] = sizes[j % len(sizes)]return datadef get_sub_html(h_type, args=[]):colorcode = {'gray': '#ECEDF2;'}if h_type == 'table0':html = "<br><table border='1' cellspacing='0' cellpadding='0' style=\" border: 1px solid #CECFD4; border-collapse: collapse; font-size: 12px; " + \"font-family: 'Helvetica Neue',Helvetica,'PingFang SC','Hiragino Sans GB','Microsoft YaHei','微软雅黑',Arial,sans-serif;\">\n"elif h_type == 'table1':html = "</table><br>\n"elif h_type == 'tr0':back_color = args[0] if len(args) > 0 else ''back_color = colorcode.get(str(back_color), '')html = '<tr style="text-align: center; vertical-align: middle; height: 30px; background-color: %s">\n' % (back_color)elif h_type == 'tr1':html = '</tr>\n'elif h_type == 'th0':rowspan = args[0] if len(args) > 0 else 1colspan = args[1] if len(args) > 1 else 1width = args[2] if len(args) > 2 else 80width = 80 if width == 0 else widthhtml = '<th colspan="%s" rowspan="%s" style="border: 1px solid #CECFD4; width:%spx;" align="center">' % (colspan, rowspan, width)elif h_type == 'th1':html = '</th>\n'elif h_type == 'td0':rowspan = args[0] if len(args) > 0 else 1colspan = args[1] if len(args) > 1 else 1width = args[2] if len(args) > 2 else 80width = 80 if width == 0 else widthhtml = '<td colspan="%s" rowspan="%s" style="border: 1px solid #CECFD4; width:%spx;" align="center">' % (colspan, rowspan, width)elif h_type == 'td1':html = '</td>\n'elif h_type == 'font0':color = args[0] if len(args) > 1 else ''size = args[1] if len(args) > 1 else ''html = '<font color="%s" size="%s">' % (color, size)elif h_type == 'font1':html = '</font>\n'else:html = ''return htmldef get_html_data(data, titles, head, widths=[]):html = get_sub_html('table0')if head is not None:html += get_sub_html('tr0', ['gray']) + \get_sub_html('th0', [1, len(titles[0])]) + str(head) + get_sub_html('th1') + \get_sub_html('tr1')for row in titles:html += get_sub_html('tr0', ['gray'])for i in range(len(row)):cell, rowspan, colspan, color, size = row[i]width = widths[i] if len(widths) > i else 80if rowspan > 0 and colspan > 0:html += get_sub_html('th0', [rowspan, colspan, width]) + get_sub_html('font0', [color, size]) + str(cell) + get_sub_html('font1') + get_sub_html('th1')#                 html += get_sub_html('th0', [rowspan, colspan, width]) + str(cell) + get_sub_html('th1')html += get_sub_html('tr1')data_colors = ['gray', 'None']color_i = 0for row in data:if row[0][1] > 0 and row[0][2] > 0:  # 换一种颜色color_i += 1this_color = data_colors[color_i % len(data_colors)]html += get_sub_html('tr0', [this_color])for i in range(len(row)):cell, rowspan, colspan, color, size = row[i]width = widths[i] if len(widths) > i else 80if rowspan > 0 and colspan > 0:html += get_sub_html('td0', [rowspan, colspan, width]) + get_sub_html('font0', [color, size]) + str(cell) + get_sub_html('font1') + get_sub_html('td1')#                 html += get_sub_html('td0', [rowspan, colspan, width]) + str(cell) + get_sub_html('td1')html += get_sub_html('tr1')html += get_sub_html('table1')return htmldef data_to_html(data, titles, head=None, datacol=0, rowspan=False, colspan=False, widths=[], font=False):'''data:数据type:二维数组titles:表头type:二维数组如果只有一行表头,可以写成[['表头1','表头2']]head:表格标题type:string默认为None,没有标题。datacol:数据起始列type:int数据列不会排序&合并,例如datacol=3,则除了前三列往后都是数据,合并时也不会进行合并rowspan:是否垂直合并value:True or False合并前请先排序,调用sort_data方法即可colspan:是否水平合并value:True or Falsewidths:每列宽度type:一维数组数组的每个值分别代表了每一列的宽度,默认80,写0也是80font:是否需要自定义字号颜色value:True or False为True时表示,需要根据需求改变字号和颜色,需要修改font_data方法'''titles = format_data(titles)data = format_data(data)if rowspan == True and datacol > 0:  # 垂直合并titles = rowspan_data(titles, len(titles[0]))data = rowspan_data(data, datacol)if colspan == True and datacol > 0:  # 水平合并titles = colspan_data(titles, len(titles[0]))data = colspan_data(data, datacol)if font == True:data = font_data(data, [])html = get_html_data(data, titles, head, widths)return htmldef get_example_data():head = '表格标题'titles = [['大表头1', '大表头1', '大表头2', '大表头3', '大表头3'],['小表头1', '小表头2', '小表头3', '小表头2', '小表头5']]data = [['小学', '语文', 1, 1, 3],['小学', '数学', 1, 5, 1],['小学', '语文', 1, 1, 33],['初中', '数学', 13, 1, 15],['高中', '数学', 1, 1, 1],['小学', '英语', 1, 8, 1],['小学汇总', '小学汇总', 1, 1, 1],['初中', '数学', 13, 1, 15],['小学', '语文', 1, 1, 33],['高中汇总', '高中汇总', 13, 1, 15]]return head, titles, datadef run_example():# 排序用的年级学科列表sorted_grade = get_sort_list('年级')sorted_subject = get_sort_list('学科')# 常规表格head, titles, data = get_example_data()html1 = data_to_html(data, titles, head)# 排序# 先用第一列按年级排序,再用第二列按学科排序,不需要排序的列可以补空数组[],前面的列排序优先级高head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html2 = data_to_html(data, titles, head)# 垂直合并表格head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html3 = data_to_html(data, titles, head, 2, True, False)# 水平合并表格head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html4 = data_to_html(data, titles, head, 2, False, True)# 垂直水平合并表格head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html5 = data_to_html(data, titles, head, 2, True, True)# 垂直水平合并表格并自定义宽度head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html6 = data_to_html(data, titles, head, 2, True, True, [160, 120, 0, 50])# 自定义颜色字号head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html7 = data_to_html(data, titles, head, 2, True, True, [], True)# 各种功能都用上试试head, titles, data = get_example_data()data = sort_data(data, [sorted_grade, sorted_subject])html8 = data_to_html(data, titles, head, 2, True, True, [160, 120, 0, 50, 200], True)mail_to = '123@qq.com'subject = '邮件主题'msg_txt = html1 + html2 + html3 + html4 + html5 + html6 + html7 + html8send_mail(mail_to, subject, msg_txt)if __name__ == '__main__':run_example()

用python生成邮件正文html表格相关推荐

  1. python 发邮件正文表格 html

    在 Python 中将表格作为电子邮件正文(不是附件)发送 参考 (详细 !清晰!)python发邮件总结及实例说明,中文乱码已解决(在最后一个模块) table-email-template Pyt ...

  2. 邮箱自动化(smtplib模块)--以邮件正文HTML表格形式

    一.需求 将工资表以邮件附件批量发送给每个人,并以HTML表格附在正文发送出去(或者发送个人业绩).解决本次需求主要用到模块为smtplib.email模块.pandas模块. 数据源 以excel表 ...

  3. 字典写入excel_使用Python扫描邮件/填写Excel表格实现办公自动化

    题图:希腊德尔斐(Delphi)神庙遗址.传说此地原为巨蟒Python盘踞,阿波罗来到此地射杀Python后建立起神庙,成为古希腊的精神圣地. 关键词:Python, 邮件扫描, yaml配置文件,邮 ...

  4. python发邮件图片太长显示不出来_小白入门,用python 发送定时邮件,将Dataframe转为邮件正文,链接显示为图片...

    在实际工作中,我们常常会遇到定时发送邮件的任务,基于我的实践,分享给大家,也许一篇文章写不完,就先列个目录. 本文想要解决的问题: 用python构造一封邮件,并设置定时发送出去.往往,这只是最低级的 ...

  5. 如何用python生成表格_用 Python 生成 HTML 表格

    在 邮件报表 之类的开发任务中,需要生成 HTML 表格. 使用 Python 生成 HTML 表格基本没啥难度, for 循环遍历一遍数据并输出标签即可. 如果需要实现合并单元格,或者按需调整表格样 ...

  6. python修改html表格,用Python生成HTML表格

    在 邮件报表 之类的开发任务中,需要生成 HTML 表格. 使用 Python 生成 HTML 表格基本没啥难度, for 循环遍历一遍数据并输出标签即可. 如果需要实现合并单元格,或者按需调整表格样 ...

  7. python 生成html表格和图片,用Python生成HTML表格的方法示例

    在 邮件报表 之类的开发任务中,需要生成HTML表格. 使用Python生成HTML表格基本没啥难度,for循环遍历一遍数据并输出标签即可. 如果需要实现合并单元格,或者按需调整表格样式,就比较麻烦了 ...

  8. 使用Python生成自动报表(Excel)以邮件发送

    数据分析师肯定每天都被各种各样的数据数据报表搞得焦头烂额,老板的,运营的.产品的等等.而且大部分报表都是重复性的工作,这篇文章就是帮助大家如何用Python来实现报表的自动发送,解放你的劳动力,可以让 ...

  9. python使用fpdf生成各种样式pdf表格数据

    python使用fpdf生成各种样式pdf表格数据 目录

最新文章

  1. kmp求前缀和后缀的最大重复部分
  2. 好久没更新日志了啊~!!今天发一个AS3的播放器
  3. grub2从usb启动
  4. 一段按页自动滚动文字或图片的Js代码
  5. 在职工象棋赛上弃子拿下一盘
  6. Url解码,兼容utf-8和gb2312
  7. Windows服务器管理(3)——IIS服务器误删了Default Web Site 网站 解决方法
  8. 中国现代远程与继续教育网 统考 大学英语(B)考试大纲
  9. Libgdx之Table 表格排版
  10. PMOS和NMOS的区分及导通方式
  11. python安全编程培训费用
  12. Ubuntu 18.04.1 LTS 安装网易云音乐,告别图标无法点击
  13. MATLAB中nargin和nargout的妙用
  14. Python基础学习之 os 模块详解
  15. 【SQL】SQL Server基础语法
  16. 不要带着这些思维去职场工作
  17. Linux 下检测磁盘坏道的方式
  18. 无线互联IOS视频教程
  19. 新一代P2P网络电视PPlive试用
  20. 字符串匹配--Sunday算法 1

热门文章

  1. iOS开发--封装的几个小动画
  2. gtx1080 matlab,深度学习主机环境配置: Ubuntu16.04+Nvidia GTX 1080+CUDA8.0
  3. 《南瓜书》PumpkinBook
  4. Linux 使用 Python 执行多线程命令
  5. 如何批量修改word文件名称?
  6. 16串口服务器在机房监控console口交换机的应用
  7. 单片机入门到高级进阶路径(附教程+工具)
  8. 基于飞桨实现项目1 车牌识别
  9. 控制PowerPoint里的Flash歌曲播放
  10. 【推荐】智慧农业解决方案资料合集30篇