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

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

作者: X_Ran_0a11 | 来源:发表于2019-07-28 02:11 被阅读0次

    一、思路

    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

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/gganlctx.html