用python生成邮件正文html表格
一、背景
在实际工作中,有时需要写个定时脚本,每天自动发报表、监控等数据。有时需要在邮件的正文展示表格。
如果使用简单的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表格相关推荐
- python 发邮件正文表格 html
在 Python 中将表格作为电子邮件正文(不是附件)发送 参考 (详细 !清晰!)python发邮件总结及实例说明,中文乱码已解决(在最后一个模块) table-email-template Pyt ...
- 邮箱自动化(smtplib模块)--以邮件正文HTML表格形式
一.需求 将工资表以邮件附件批量发送给每个人,并以HTML表格附在正文发送出去(或者发送个人业绩).解决本次需求主要用到模块为smtplib.email模块.pandas模块. 数据源 以excel表 ...
- 字典写入excel_使用Python扫描邮件/填写Excel表格实现办公自动化
题图:希腊德尔斐(Delphi)神庙遗址.传说此地原为巨蟒Python盘踞,阿波罗来到此地射杀Python后建立起神庙,成为古希腊的精神圣地. 关键词:Python, 邮件扫描, yaml配置文件,邮 ...
- python发邮件图片太长显示不出来_小白入门,用python 发送定时邮件,将Dataframe转为邮件正文,链接显示为图片...
在实际工作中,我们常常会遇到定时发送邮件的任务,基于我的实践,分享给大家,也许一篇文章写不完,就先列个目录. 本文想要解决的问题: 用python构造一封邮件,并设置定时发送出去.往往,这只是最低级的 ...
- 如何用python生成表格_用 Python 生成 HTML 表格
在 邮件报表 之类的开发任务中,需要生成 HTML 表格. 使用 Python 生成 HTML 表格基本没啥难度, for 循环遍历一遍数据并输出标签即可. 如果需要实现合并单元格,或者按需调整表格样 ...
- python修改html表格,用Python生成HTML表格
在 邮件报表 之类的开发任务中,需要生成 HTML 表格. 使用 Python 生成 HTML 表格基本没啥难度, for 循环遍历一遍数据并输出标签即可. 如果需要实现合并单元格,或者按需调整表格样 ...
- python 生成html表格和图片,用Python生成HTML表格的方法示例
在 邮件报表 之类的开发任务中,需要生成HTML表格. 使用Python生成HTML表格基本没啥难度,for循环遍历一遍数据并输出标签即可. 如果需要实现合并单元格,或者按需调整表格样式,就比较麻烦了 ...
- 使用Python生成自动报表(Excel)以邮件发送
数据分析师肯定每天都被各种各样的数据数据报表搞得焦头烂额,老板的,运营的.产品的等等.而且大部分报表都是重复性的工作,这篇文章就是帮助大家如何用Python来实现报表的自动发送,解放你的劳动力,可以让 ...
- python使用fpdf生成各种样式pdf表格数据
python使用fpdf生成各种样式pdf表格数据 目录
最新文章
- kmp求前缀和后缀的最大重复部分
- 好久没更新日志了啊~!!今天发一个AS3的播放器
- grub2从usb启动
- 一段按页自动滚动文字或图片的Js代码
- 在职工象棋赛上弃子拿下一盘
- Url解码,兼容utf-8和gb2312
- Windows服务器管理(3)——IIS服务器误删了Default Web Site 网站 解决方法
- 中国现代远程与继续教育网 统考 大学英语(B)考试大纲
- Libgdx之Table 表格排版
- PMOS和NMOS的区分及导通方式
- python安全编程培训费用
- Ubuntu 18.04.1 LTS 安装网易云音乐,告别图标无法点击
- MATLAB中nargin和nargout的妙用
- Python基础学习之 os 模块详解
- 【SQL】SQL Server基础语法
- 不要带着这些思维去职场工作
- Linux 下检测磁盘坏道的方式
- 无线互联IOS视频教程
- 新一代P2P网络电视PPlive试用
- 字符串匹配--Sunday算法 1