使用Python發送郵件(圖片、表格、附件) 系列三: 發送工作報表之透視表自動刷新數據

使用Python發送郵件(圖片、表格、附件) 系列一:如何發送圖片、表格等的全代碼

https://blog.csdn.net/u010652755/article/details/104321413

使用Python發送郵件(圖片、表格、附件) 系列二: 同時發送圖片和附件實際案例

https://blog.csdn.net/u010652755/article/details/104321576

本文是第系列三,可用於工作中使用python發送定時報表。發送報表時經常用到透視表,本文即解決了兩個問題:

1、將透視表表格轉爲圖片內嵌到郵件正文中,此處只寫了了只有一張簡單彙總透視表的情況

2、在第一份透視表中勾選【打開自動更新】選項(可百度),當透視表的原數據發生變化,打開透視表數據會自動刷新。下載郵件中的透視表打開,點擊【啓用編輯】【啓用保護內容】,即可實現數據刷新

注意:將透視表和數據源放到指定目錄中,兩個文件的格式名字不要有變動,每天用新的數據源將舊數據源覆蓋即可

 

# -*- coding: utf-8 -*-
"""
Created on Sat Feb 15 11:44:58 2020

@author: xxxx
"""

import os
os.chdir(r'F:\自動化報表\python_excel')

import numpy as np
import pandas as pd


import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['Times New Roman Uni']
mpl.rcParams['font.serif'] = ['Times New Roman Uni']
mpl.rcParams['axes.unicode_minus'] = False

import smtplib
from email.message import EmailMessage
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication

# 顯示所有內容
pd.set_option('max_colwidth',100)

#%% 發送郵件
def send_email():

    mail_user = 'xxxx'    # 郵箱登錄名,次處使用QQ郵箱,填寫QQ號即可,不用帶@qq.com
    mail_pass = 'xxxx'    # QQ郵箱授權碼,可百度如何獲取

    sender    = '[email protected]'   # 發件人
    receivers = ['xxxx']  		# 收件人列表,list形式
    chaosong  = ['xxxx'] 		# 抄送人列表,list形式

    # 設置郵件體對象,對象類型爲 mixed,可以發送附件
    subject = """使用Python發送自動化報表"""	# 郵件主題
    msg = MIMEMultipart()                       # 郵件體對象,此處可加入參數, 具體可百度
    msg['subject'] = Header(subject, 'utf-8')   # 加入郵件主題
    msg['From'] = "{}".format(sender)           # 加入郵件發送人
    msg['To'] = ",".join(receivers)             # 加入郵件接收人
    msg['Cc'] = ",".join(chaosong)              # 加入郵件抄送人,如無,可註釋掉

    # 加入圖片
    htmlFile = """\
    <html>
      <head></head>
      <body>
        <pre style="font-family:arial; margin: left;">
        Dears,
           以下是某銷售產品的每日統計數據,請查收.詳細數據見附件

        表1 各地線上及線下銷售總額(億元):
        <img src="cid:0" >
        </pre>
      </body>
    </html>
    """
    htmlApart = MIMEText(htmlFile, 'html')

    # 在正文中顯示圖片
    File1 = 'data_image.png' # 如果是定時發送的報表,此處可以寫死
    imageApart = MIMEImage(open(File1, 'rb').read(), File1.split('.')[-1])
    imageApart.add_header('Content-ID', '<0>')
    msg.attach(imageApart)
    msg.attach(htmlApart)


    # 加入附件
    File2 = '每日統計透視表.xlsx' # 如果是定時發送的報表,此處可以寫死
    attFile = MIMEApplication(open(File2, 'rb').read())
    attFile.add_header('Content-Disposition', 'attachment', filename=File2)
    msg.attach(attFile)


    if __name__ == '__main__' :
        try:
            # 發送郵件,參數設置
            sftp_obj = smtplib.SMTP_SSL(host='smtp.qq.com', port = 465)
            sftp_obj.login(mail_user, mail_pass)
            sftp_obj.sendmail(sender, receivers, msg.as_string())
            sftp_obj.quit()
            sftp_obj.close()
            print('\nThe email has been sent successfully')
        except Exception as err:
            print('\n Email failed to be sent out. Please check !')
            print(err)

#%% 設置表格樣式
def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,
                     header_color='#40466e', row_colors=['#f1f1f2', 'w'], edge_color='black',
                     bbox=[0, 0, 1, 1], header_columns=0, ax=None,
                     cell_width = None, **kwargs):

    data_shape = data.shape

    if ax is None:
        size = (np.array(data.shape[::-1]) + np.array([0, 1])) * np.array([col_width, row_height])
        fig, ax = plt.subplots(figsize=size)
        ax.axis('off')

    mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=data.columns, cellLoc='center', **kwargs)
    mpl_table.auto_set_font_size(False)
    mpl_table.set_fontsize(font_size)
    mpl_table.set_gid('-')

    for k, cell in  mpl_table._cells.items():
        if cell_width is None:
            pass
        else:
            cell.set_width(cell_width[k[1]])
        cell.set_edgecolor(edge_color)
        if k[0] == 0 or k[1] < header_columns or k[0] == data_shape[0]:
            cell.set_text_props(weight='bold', color='w')
            cell.set_facecolor(header_color)
        else:
            cell.set_facecolor(row_colors[k[0]%len(row_colors) ])

    fig.savefig('data_image.png', bbox_inches = 'tight')
#    plt.show()
    return ax


#%%
# 數據處理
# 1、 修改原數據後再次發送查看郵件透視表,爲了進行測試,修改了透視表源數據
df = pd.read_csv('5000 Sales Records.csv')
df['Total Revenue'] = 5
df.to_excel('sales_data.xlsx', sheet_name='5000 Sales Records', index=False)

# 2、透視表:如果不在正文中顯示透視表內容,只是將透視表作爲附件發送,則無需加入本部分的代碼,只用1、3、4部分即可
df_pivot = df.groupby('Region', as_index=False)['Order Priority', 'Total Revenue', 'Total Cost', 'Total Profit'].\
          agg({'Order Priority':len, 'Total Revenue':sum, 'Total Cost': sum, 'Total Profit':sum})
sum_all = dict(zip(list(df_pivot.columns), ['總計'] + list(df_pivot.iloc[:, 1:].sum())))
df_pivot = df_pivot.append([sum_all], ignore_index=True)
df_pivot.iloc[:, 2:] = df_pivot.iloc[:, 2:].applymap(lambda x: str("{:.2f}".format(x)) )

# 3、讀取透視表數據,此時python讀取的透視表數據並沒有更新。
# 在透視表中透視表選項中勾選【打開時更新數據】,那麼在郵件中打開透視表時,可以發現透視表更新了
dfp = pd.read_excel('每日統計透視表.xlsx') # 透視表源表爲 sales_data.xlsx
dfp.iloc[:, 2:] = dfp.iloc[:, 2:].applymap(lambda x: str("{:.2f}".format(x)) ) #處理顯示小數位數

# 4、發送郵件
render_mpl_table(df_pivot, header_columns=0, col_width=3, cell_width = [0.20, 0.10, 0.10, 0.10, 0.10])
send_email()

圖1  數據源改動前郵件內容

 

圖2  數據源改動後郵件內容(數據因爲由0改爲了5,所以和上圖對不上)

 

參考資料:

1、matplotlib 使用 plt.savefig() 輸出圖片去除旁邊的空白區域:https://blog.csdn.net/jifaley/article/details/79687000 

2、matplotlib繪圖:https://matplotlib.org/3.1.0/api/pyplot_summary.html

3、表格轉圖片代碼:https://code-examples.net/en/q/19714c3

       Python發送郵件系列已全部完成,本文涉及的只是如何發送郵件的代碼。當然,在實際工作中,要處理的任務比這個要更復雜一些,比如連接數據庫,多級透視表,多張報表和圖表等。最後,感謝諸位網友的不吝分享,也希望本文能對大家有所幫助,減少重複的工作,提升工作效率。。

發佈了25 篇原創文章 · 獲贊 13 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章