python

【案例-自动化报表】mysql数据+python报表和发送邮件

2019-07-28  本文已影响0人  X_Ran_0a11

一、思路

1、mysql创建表wy_user,包含用户信息和用户邮箱;
2、mysql创建表wy_user_data,包含用户用电信息;
3、python读取mysql的两个表,形成自动化报表(文字+图);
4、python将形成的报表发送至用户邮箱。

二、执行

1、mysql的user表

CREATE SCHEMA `mysql_python` ;
use mysql_python;
CREATE TABLE `mysql_python`.`wy_user` (
  `id` INT NOT NULL,
  `name` VARCHAR(45) NULL,
  `email_address` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));
INSERT INTO `mysql_python`.`wy_user` (`id`, `name`, `email_address`) VALUES ('1', '张三', 'xxxxxxx@qq.com');
INSERT INTO `mysql_python`.`wy_user` (`id`, `name`, `email_address`) VALUES ('2', '李四', 'xxxxxxx@qq.com');

结果:


image.png

2、mysql的data表

CREATE TABLE `mysql_python`.`wy_user_data` (
  `id` INT NOT NULL,
  `Q1` INT NULL,  `Q2` INT NULL,  `Q3` INT NULL,
  `Q4` INT NULL,  `Q5` INT NULL,  `Q6` INT NULL,
  `Q7` INT NULL,  `Q8` INT NULL,  `Q9` INT NULL,
  `Q10` INT NULL,  `Q11` INT NULL,  `Q12` INT NULL,
  `Q13` INT NULL,  `Q14` INT NULL,  `Q15` INT NULL,
  `Q16` INT NULL,  `Q17` INT NULL, `Q18` INT NULL,
  `Q19` INT NULL, `Q20` INT NULL,  `Q21` INT NULL,
  `Q22` INT NULL,  `Q23` INT NULL, `Q24` INT NULL,
  PRIMARY KEY (`id`));
INSERT INTO `mysql_python`.`wy_user_data` (`id`, `Q1`, `Q2`, `Q3`, `Q4`, `Q5`, `Q6`, `Q7`, `Q8`, `Q9`, `Q10`, `Q11`, `Q12`, `Q13`, `Q14`, `Q15`, `Q16`, `Q17`, `Q18`, `Q19`, `Q20`, `Q21`, `Q22`, `Q23`, `Q24`) VALUES ('1', '200', '322', '450', '511', '645', '111', '234', '564', '1234', '1234', '452', '1234', '1234', '102', '046', '1023', '1054', '503', '432', '346', '275', '345', '456', '880');
INSERT INTO `mysql_python`.`wy_user_data` (`id`, `Q1`, `Q2`, `Q3`, `Q4`, `Q5`, `Q6`, `Q7`, `Q8`, `Q9`, `Q10`, `Q11`, `Q12`, `Q13`, `Q14`, `Q15`, `Q16`, `Q17`, `Q18`, `Q19`, `Q20`, `Q21`, `Q22`, `Q23`, `Q24`) VALUES ('2', '30', '246', '304', '241', '0054', '204', '213', '459', '42', '1234', '105', '2014', '243', '895', '940', '1054', '234', '1247', '243', '220', '189', '204', '36', '55');

结果:


image.png

3、python形成报表

# -*- coding:utf-8 -*-
import pymysql
import pandas as pd
from docx import Document
from docx.shared import Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_TAB_ALIGNMENT, WD_TAB_LEADER
import time
import seaborn as sns
import matplotlib.pyplot as plt

# 取表(定义函数一直有点问题,所以就不定义了)
# 连接数据库
db = pymysql.connect("xxx.mysql.rds.aliyuncs.com", "xxx", "xxx", "mysql_python")
cursor = db.cursor()
sql1 = 'select * from wy_user'
sql2 = 'select * from wy_user_data'
cursor.execute(sql1)
user = cursor.fetchall()
columnDes = cursor.description  # 获取描述信息
columnNames = [columnDes[i][0] for i in range(len(columnDes))]
user_df = pd.DataFrame([list(i) for i in user], columns=columnNames)
user_df.set_index('id', inplace=True)

cursor.execute(sql2)
user_data = cursor.fetchall()
columnDes = cursor.description  # 获取描述信息
columnNames = [columnDes[i][0] for i in range(len(columnDes))]
user_data_df = pd.DataFrame([list(i) for i in user_data], columns=columnNames)
user_data_df.set_index('id', inplace=True)

# python报表

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

for id in range(2):
    #数据准备
    name = user_df.iloc[id]['name']
    all_value = user_data_df.iloc[id].sum()
    high_value = user_data_df.iloc[id][7:11].sum() + user_data_df.iloc[id][19:23].sum()
    flat_value = user_data_df.iloc[id][11:19].sum()
    valley_value = user_data_df.iloc[id].sum() - high_value - flat_value
    #图片准备
    fig, ax = plt.subplots(figsize=(10, 5))
    plt.title("Electricity-Quantity Distribution", fontsize=15)
    plt.xticks(rotation=90)
    plt.xlabel('Time Scale', fontsize=12)
    plt.ylabel('Volumn(kWh)', fontsize=12)
    sns.barplot(x=list(user_data_df.columns), y=list(user_data_df.iloc[id]))
    plt.savefig('/Users/ranmo/Desktop/数据分析案例/自动化报表/%d.jpg' % (id + 1))

    # 创建文档
    document = Document()
    # 标题
    year = int(time.strftime('%Y', time.localtime()))
    month = int(time.strftime('%m', time.localtime())) - 1

    title = ('%d年%d月客户用电分析报告' % (year, month))
    document.add_heading(title, 0)

    # 开头
    head = document.add_heading('尊敬的  ', level=1)
    head.add_run(name).italic = True
    head.add_run('  客户:')

    # 正文

    p = document.add_paragraph('    您好!')
    p.add_run('您%d年%d月的总用电量为%d千瓦时,其中峰、平、谷段的电量分别为:%d千瓦时、%d千瓦时以及%d千瓦时。具体用电情况如下图所示:' % (
    year, month, all_value, high_value, flat_value, valley_value))
    document.add_picture('/Users/ranmo/Desktop/数据分析案例/自动化报表/%d.jpg' % (id + 1), width=Inches(6))
    document.add_paragraph('')
    document.add_paragraph('')
    document.add_paragraph('')

    a = document.add_paragraph()
    a.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.RIGHT  # 段落文字居右设置
    a.add_run('wy公司')

    b = document.add_paragraph()
    b.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.RIGHT  # 段落文字居右设置
    b.add_run('%d年%d月01日' % (year, (month+1)))

    document.save('/Users/ranmo/Desktop/数据分析案例/自动化报表/%d_%s_报告.docx'%(id+1,name))

python生成word:
https://python-docx.readthedocs.io/en/latest/
https://www.cnblogs.com/xiao987334176/p/9995976.html

(本来还想把word转成pdf再发送的,但是api好像都是win环境的)

4、定时发送用户邮箱
a.python代码发送用户邮箱:

# -*- coding:utf-8 -*-

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header

import pymysql
import pandas as pd

db = pymysql.connect("xxx.mysql.rds.aliyuncs.com", "xxx", "xxx", "mysql_python")
cursor = db.cursor()
sql1 = 'select * from wy_user'
cursor.execute(sql1)
user = cursor.fetchall()
columnDes = cursor.description  # 获取描述信息
columnNames = [columnDes[i][0] for i in range(len(columnDes))]
user_df = pd.DataFrame([list(i) for i in user], columns=columnNames)
user_df.set_index('id', inplace=True)
cursor.close()


for id in range(2):
    my_sender = 'xxx'
    my_pass = 'xxx'
    my_user = user_df.iloc[id]['email_address']  # 接收邮件
    name = user_df.iloc[id]['name']

    #创建一个带附件的实例
    message = MIMEMultipart()
    message['From'] = Header("Arthur", 'utf-8')
    message['To'] =  Header(name, 'utf-8')
    subject = '客户用电分析报告'
    message['Subject'] = Header(subject, 'utf-8')

    #邮件正文内容
    message.attach(MIMEText('您好!这是您上月的用电分析报告,请查收!', 'plain', 'utf-8'))

    # 构造附件1,传送当前目录下的 test.txt 文件
    att1 = MIMEText(open('/Users/ranmo/Desktop/数据分析案例/自动化报表/%d_%s_报告.docx'%(id+1,name), 'rb').read(), 'base64', 'utf-8')
    att1["Content-Type"] = 'application/octet-stream'
    # 这里的filename可以任意写,写什么名字,邮件中显示什么名字
    att1.add_header("Content-Disposition", "attachment", filename=("utf-8", "", "%d_%s_报告.docx"%(id+1,name)))
    message.attach(att1)



    try:
        server=smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的SMTP服务器,端口是465
        server.login(my_sender, my_pass)  # 括号中对应的是发件人邮箱账号、邮箱密码
        server.sendmail(my_sender,my_user,message.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
        server.quit()  # 关闭连接
        print ("邮件发送成功")
    except smtplib.SMTPException:
        print ("Error: 无法发送邮件")

python发送邮件:
https://www.runoob.com/python3/python3-smtp.html

b.编写定时执行脚本

#!/bin/bash
# -*- coding: utf-8 -*-
cd /Users/ranmo/Desktop/数据分析案例/自动化报表
python3 auto-word.py
python3 Email-Sending.py

* * * * *  /Users/ranmo/Desktop/数据分析案例/自动化报表/auto-word-sending.sh

crontab定时器:
https://blog.csdn.net/ty_hf/article/details/72354230
http://www.shanhuxueyuan.com/news/detail/118.html

ps:写crontab脚本的时候,遇到环境变量配置问题,最后发展成了“拯救环境变量三连”:
1、export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
2、open -e ~/.bash_profile
3、source ~/.bash_profile
结论就是,有的路径不能往配置里面写。。不然会导致崩溃。
https://blog.csdn.net/haishen111/article/details/88867968

我写好了脚本,可以直接拖到终端执行,但是crontab提示“python3: command not found”,查询了半天,可能是因为crontab里面调用py,必须指定解释器的路径
https://www.cnblogs.com/zhhiyp/p/10160754.html
原执行脚本修改为:

#!/bin/bash
# -*- coding: utf-8 -*-
cd /Users/ranmo/Desktop/数据分析案例/自动化报表
/Users/ranmo/anaconda3/bin/python3 auto-word.py
/Users/ranmo/anaconda3/bin/python3 Email-Sending.py

搞定!

三、结果
1、收到邮件


image.png

2、邮件附件


image.png
上一篇下一篇

猜你喜欢

热点阅读