使用 Python 根据磁盘使用情况在 HTML 表格电子邮件正文中添加标题和文本颜色
Posted
技术标签:
【中文标题】使用 Python 根据磁盘使用情况在 HTML 表格电子邮件正文中添加标题和文本颜色【英文标题】:Add header and text color in HTML table email body based on disk usage condition using Python 【发布时间】:2022-01-13 01:09:56 【问题描述】:我正在使用 python 在电子邮件正文中发送一个 html 表格。 html 表由磁盘使用情况组成,当磁盘使用率高于 80% 时,我需要在表中添加标题(第一行)和红色文本。
这是我正在使用的代码,用于获取带有文本颜色的电子邮件,但它不包括标题(服务器、总大小、总数据、使用百分比):
me = 'noreply@automationtest.com'
server = 'some smtp server'
you = 'email@someautomation.com'
text = """
table
"""
html = """
<html>
<head>
<style>
table, th, td border: 1px solid black; border-collapse: collapse;
th, td padding: 5px;
</style>
</head>
<body><p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
table
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body></html>
"""
with open('files/file.csv') as input_file:
reader = DictReader(input_file)
data = list(reader)
for row in data:
row['Usage in %'] = pd.to_numeric(row['Usage in %'])
if row['Usage in %'] >= 80:
row['Usage in %'] = "<p style='color:red'>%s</p>"%row['Usage in %']
text = text.format(table=tabulate(data, headers="firstrow", tablefmt="grid"))
html = html.format(table=tabulate(data, headers="firstrow", tablefmt="unsafehtml"))
message = MIMEMultipart("alternative", None, [MIMEText(text), MIMEText(html,'html')])
print(html)
message['From'] = me
message['To'] = you
server = smtplib.SMTP(server)
server.ehlo()
server.starttls()
server.login(me, password)
server.sendmail(me, you, message.as_string())
server.quit()
我得到以下带有文本颜色但没有标题的输出:
预期输出:
非常感谢任何帮助。
【问题讨论】:
【参考方案1】:在pandas 1.3.0 及更新版本中,最合适的方式是使用pandas Table Visualization 并创建一个Subclass
创建一个文件夹“templates”和两个文件“myhtml.tpl”和“mystyles.tpl”
在 myhtml.tpl 中添加所需的任何额外 HTML 代码:
% extends "html_table.tpl" %
% block table %
<p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
super()
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
% endblock table %
在 mystyles.tpl 添加任何其他样式:
% extends "html_style.tpl" %
% block style %
super()
<style>
table, th, td
border: 1px solid black;
border-collapse: collapse;
th, td
padding: 5px;
</style>
% endblock style %
(生成此文件结构的代码在此答案的末尾)
我们现在可以使用from_custom_template
生成Styler
子类
import numpy as np
import pandas as pd
from pandas.io.formats.style import Styler
# Build Styler Subclass from templates
MyStyler = Styler.from_custom_template(
"templates", # Folder to Search
html_table="myhtml.tpl", # HTML Template
html_style='mystyles.tpl' # CSS Template
)
# trim extra whitespace from HTML
MyStyler.env.trim_blocks = True
# Read in CSV
df = pd.read_csv('files/file.csv')
# Add styles using Styler apply and render to_html
html = MyStyler(df).apply(
lambda s: np.where(s >= 80, 'color: red', None), subset='Usage in %'
).format(
# Apply format string (remove insignificant zeros)
formatter=':g', subset='Usage in %'
).hide_index().to_html(doctype_html=True)
print(html)
生成的 html 字符串类似于:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
#T_22fdb_row2_col3,
#T_22fdb_row3_col3
color: red;
</style>
<style>
table,
th,
td
border: 1px solid black;
border-collapse: collapse;
th,
td
padding: 5px;
</style>
</head>
<body>
<p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
<table id="T_22fdb_">
<thead>
<tr>
<th class="col_heading level0 col0">Server</th>
<th class="col_heading level0 col1">Total size</th>
<th class="col_heading level0 col2">Total Data in</th>
<th class="col_heading level0 col3">Usage in %</th>
</tr>
</thead>
<tbody>
<tr>
<td id="T_22fdb_row0_col0" class="data row0 col0">A</td>
<td id="T_22fdb_row0_col1" class="data row0 col1">100</td>
<td id="T_22fdb_row0_col2" class="data row0 col2">25</td>
<td id="T_22fdb_row0_col3" class="data row0 col3">25</td>
</tr>
<tr>
<td id="T_22fdb_row1_col0" class="data row1 col0">B</td>
<td id="T_22fdb_row1_col1" class="data row1 col1">100</td>
<td id="T_22fdb_row1_col2" class="data row1 col2">20</td>
<td id="T_22fdb_row1_col3" class="data row1 col3">20</td>
</tr>
<tr>
<td id="T_22fdb_row2_col0" class="data row2 col0">C</td>
<td id="T_22fdb_row2_col1" class="data row2 col1">100</td>
<td id="T_22fdb_row2_col2" class="data row2 col2">85</td>
<td id="T_22fdb_row2_col3" class="data row2 col3">85.6</td>
</tr>
<tr>
<td id="T_22fdb_row3_col0" class="data row3 col0">D</td>
<td id="T_22fdb_row3_col1" class="data row3 col1">100</td>
<td id="T_22fdb_row3_col2" class="data row3 col2">90</td>
<td id="T_22fdb_row3_col3" class="data row3 col3">90.8</td>
</tr>
</tbody>
</table>
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body>
</html>
解决这个问题的更简单的方法是直接使用格式化操作 html 字符串,但是,这可能会导致 html 格式不正确:
import numpy as np
import pandas as pd
html = """
<html>
<head>
<style>
table, th, td border: 1px solid black; border-collapse: collapse;
th, td padding: 5px;
</style>
</head>
<body><p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
table
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body></html>
"""
# Read in CSV
df = pd.read_csv('files/file.csv')
# Add styles using Styler apply and render to_html
table_html = df.style.apply(
lambda s: np.where(s >= 80, 'color: red', None), subset='Usage in %'
).format(
# Apply format string (remove insignificant zeros)
formatter=':g', subset=['Total Data in', 'Usage in %']
).hide_index().to_html()
html = html.format(table=table_html)
print(html)
这会导致以下 html(注意样式元素放错位置):
<html>
<head>
<style>
table, th, td border: 1px solid black; border-collapse: collapse;
th, td padding: 5px;
</style>
</head>
<body><p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
<style type="text/css">
#T_139a3_row2_col3, #T_139a3_row3_col3
color: red;
</style>
<table id="T_139a3_">
<thead>
<tr>
<th class="col_heading level0 col0" >Server</th>
<th class="col_heading level0 col1" >Total size</th>
<th class="col_heading level0 col2" >Total Data in</th>
<th class="col_heading level0 col3" >Usage in %</th>
</tr>
</thead>
<tbody>
<tr>
<td id="T_139a3_row0_col0" class="data row0 col0" >A</td>
<td id="T_139a3_row0_col1" class="data row0 col1" >100</td>
<td id="T_139a3_row0_col2" class="data row0 col2" >25</td>
<td id="T_139a3_row0_col3" class="data row0 col3" >25</td>
</tr>
<tr>
<td id="T_139a3_row1_col0" class="data row1 col0" >B</td>
<td id="T_139a3_row1_col1" class="data row1 col1" >100</td>
<td id="T_139a3_row1_col2" class="data row1 col2" >20</td>
<td id="T_139a3_row1_col3" class="data row1 col3" >20</td>
</tr>
<tr>
<td id="T_139a3_row2_col0" class="data row2 col0" >C</td>
<td id="T_139a3_row2_col1" class="data row2 col1" >100</td>
<td id="T_139a3_row2_col2" class="data row2 col2" >85</td>
<td id="T_139a3_row2_col3" class="data row2 col3" >85.6</td>
</tr>
<tr>
<td id="T_139a3_row3_col0" class="data row3 col0" >D</td>
<td id="T_139a3_row3_col1" class="data row3 col1" >100</td>
<td id="T_139a3_row3_col2" class="data row3 col2" >90</td>
<td id="T_139a3_row3_col3" class="data row3 col3" >90.8</td>
</tr>
</tbody>
</table>
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
</body></html>
构建模板文件夹和两个模板文件的简单脚本:
import pathlib
# Code to generate the Templates and folder
pathlib.Path('./templates').mkdir(exist_ok=True)
with open('./templates/myhtml.tpl', 'w') as f:
f.write('''
% extends "html_table.tpl" %
% block table %
<p style="font-family:verdana">Hi,</p>
<p style="font-family:verdana">sometext</p>
super()
<p style="font-family:verdana">sometext</p>
<p style="font-family:verdana">Regards</p>
<p style="font-family:verdana">someme</p>
% endblock table %
'''.strip())
with open('./templates/mystyles.tpl', 'w') as f:
f.write('''
% extends "html_style.tpl" %
% block style %
super()
<style>
table, th, td
border: 1px solid black;
border-collapse: collapse;
th, td
padding: 5px;
</style>
% endblock style %
'''.strip())
files/file.csv
内容:
Server,Total size,Total Data in,Usage in %
A,100,25,25
B,100,20,20
C,100,85,85.6
D,100,90,90.8
【讨论】:
嗨@Henry,非常感谢您的回复。这很棒并且按预期工作。但是,当我在 csv 文件中添加小数时(例如:85.5 和 90.7),我得到了额外的零,我进入了 htmlsubset
从subset='Usage in %'
更改为列表subset=['Total Data in', 'Usage in %']
来包含多个列(例如)。以上是关于使用 Python 根据磁盘使用情况在 HTML 表格电子邮件正文中添加标题和文本颜色的主要内容,如果未能解决你的问题,请参考以下文章