用python的pymysql模块实现数据库查询数据,使用openpyxl模块导出数据到Excel中并邮件发送

本文介绍了一个简单的Python脚本,用于自动化从数据库提取销售记录,将其导出到Excel文件,并通过电子邮件自动发送给指定收件人。脚本使用pymysql连接数据库,openpyxl操作Excel,smtplib发送邮件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求分析

公司业务提出需求,需要将数据库的销售记录导出到excel给她们。并且每天都要给。。我特喵
想了想也很简单,写个脚本从数据库查询数据并导出到excel,然后做个定时任务每天定时发邮件给他们不就完事儿了吗~So easy!
不说了,开撸!
首先安装需要用到的包

#与数据库打交道的模块,可以连接数据库,查询数据等
pip3 install pymysql
#与Excel打交道的模块,可以读取,写入数据到excel,以及一系列的excel操作
pip3 install openpyxl

话不多说,上代码

import os
import pymysql
import smtplib
from openpyxl import Workbook
from openpyxl.utils import get_column_letter
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

class SelectData(object):
    def __init__(self,sql_items):
        self.sql_items = sql_items

    def select_sql(self):
        sheet_item = []   #定义一个空列表,存放查询到的数据
        for i in self.sql_items:    #遍历所有的SQL项目
            sql_query = i['sql_query']  #获取当前SQL项目中的SQL语句
            db_info = i['db']   #获取当前SQL项目中的数据库连接信息
            #生成一个数据库连接
            try:
                db = pymysql.connect(host=db_info['host'],user=db_info['user'],password=db_info['password'],database=db_info['database'],port=db_info['port'],charset=db_info['charset'])
            except Exception as e:
                print(f'数据库连接失败:{e}')
                continue
            cursor = db.cursor() #生成一个数据库游标
            cursor.execute(sql_query)  #用游标运行SQL语句,查询数据
            col = cursor.description  # 获取列名作为Excel的表头
            results = cursor.fetchall() #获取查询到的数据
            if not results:
                #判断当前SQL项目查询是否有数据,如果查询结果为空,则进入下一个循环
                continue
            cursor.close()  #关闭游标
            db.close()  #关闭数据库连接
            #将查询到的数据以字典的形式存储
            items = {
                'sheet_name': i['sheet_name'],  #写入的Excel的Sheet名
                'results': results,     # 查询结果数据
                'col': col,     #列名
            }
            sheet_item.append(items)   #将查询到的数据添加到数据列表
        if not sheet_item:
            #判断数据列表是否有数据,如果没有返回空
            return
        return sheet_item   #返回数据列表

class WriteExcel(object):
    """
    写入数据到excel
    """
    def __init__(self,sheet_item,save_path):
        self.sheet_item = sheet_item     # 接收数据列表
        self.save_path = save_path       # 接收excel保存路径

    def _get_maxcol(self,results,columnName):
        ##获取表格存放的数据的最大列宽,自适应调整列宽
        columnName_len = [] #定义一个存放列宽大小的列表
        for n in range(len(columnName)):  #遍历列名
            max_len = 10
            column_len = len(str(columnName[n]).encode('utf-8'))  #列名长度
            if  column_len > max_len:   #判断如果列名长度大于10的话,就替换最大长度
                max_len = column_len
            for row in range(len(results)):  #循环遍历每行数据中第n列的数据
                data = str(results[row][n])  #取出第row行的数据
                data_len = len(data.encode('utf-8'))  #判断此数据的长度
                if data_len > max_len:    #如果次数据的长度大于max_len则max_len等于此数据的长度。
                    max_len = data_len
                elif data_len > 100:   #如果此数据的长度大于100,则取列宽为100,单列太宽了没法看。。
                    max_len = 100
            columnName_len.append(max_len) #将最大列宽加入到列宽的列表中
        return columnName_len   #返回列宽列表

    def write_excel(self):
        wb = Workbook()  #生成一个excel的workbook对象
        aaa = wb.active   #第一个sheet
        for item in self.sheet_item:   #循环遍历接收到的数据列表
            results = item['results']  #查询结果数据
            columnName = []  #定义一个excel列名列表
            for c in item['col']:    #循环遍历数据库中返回的列名元组信息
                columnName.append(c[0])   #获取列名的字符串,并添加到列名列表
            columnName_len = self._get_maxcol(results,columnName)   #获取每列的最大列宽值
            rows = len(results)   #数据结果的长度即为excel的数据行数
            sheet_name = item['sheet_name'] #sheet名
            sheet = wb.create_sheet(title=sheet_name)    #创建一个sheet对象
            for i in range(1, len(columnName) + 1):    #循环遍历列名列表,并将列名写入sheet对象的首行
                col_letter = get_column_letter(i)  #获取此列对应的字母,比如第一列对应的为A
                col_len = columnName_len[i-1]  #获取此列的列宽值
                sheet.column_dimensions[col_letter].width = col_len  #设置此列的宽度
                sheet.cell(row=1, column=i, value=columnName[i - 1]) #将列名写入表格
            for n in range(1,rows+1):   #循环遍历总行数
                for j in range(1,len(columnName)+1): #循环遍历列数
                    sheet.cell(row=n+1,column=j,value=results[n-1][j-1]) #将对应的行列坐标的数据写入excel
        wb.remove(aaa)   #移除第一个sheet
        wb.save(self.save_path)   #保存excel到指定的路径

class SendMail(object):
    def __init__(self,save_path,excel_name,to_mail_addr,cc_mail_addr):
        self.save_path = save_path     #接收excel的保存路径
        self.excel_name = excel_name    #接收excel名
        self.to_mail_addr = to_mail_addr  #接收收件人邮件地址
        self.cc_mail_addr = cc_mail_addr  #接收抄送人邮件地址

    def send_mail(self):
        username = 'aaa@163.com'   #发件人邮箱
        password='*********'      #发件人邮箱密码
        sender='aaa@163.com'   #显示的发件人
        receiver = self.to_mail_addr + self.cc_mail_addr  #接收邮件的收件人
        if not receiver:
            return '没有收件人!邮件未发送'
        subject = '%s报表' % self.excel_name    #邮件主题
        msg = MIMEMultipart('mixed')     #定义一个msg对象
        msg['Subject'] = subject        #显示的邮件主题
        msg['From'] = 'aaa <aaa@163.com>'  #显示的发件人信息
        msg['To'] = ";".join(self.to_mail_addr)    #显示的收件人信息
        msg['Cc'] = ';'.join(self.cc_mail_addr)    #显示的抄送人信息

        text = "Dear All:\n\n附件是%s,请查收。" % self.excel_name   #邮件的文本内容
        text_plain = MIMEText(text,'plain', 'utf-8')               #设置邮件的文本格式为text,也可以为html
        msg.attach(text_plain)    #将文本添加到msg对象

        sendfile = open(self.save_path,'rb').read()     #读取要发送的附件文件
        text_att = MIMEText(sendfile, 'base64', 'utf-8')  #将附件添加到邮件的正文文本
        text_att["Content-Type"] = 'application/octet-stream'
        text_att.add_header('Content-Disposition', 'attachment', filename='%s' % self.excel_name)   #附件显示名
        msg.attach(text_att)  #将附件信息添加到msg对象中

        smtp = smtplib.SMTP(host='smtp.163.com')   #定义一个smtp发件服务器信息
        smtp.connect('smtp.163.com',25)       #连接smtp发件服务器
        smtp.starttls()                 #以加密的方式通信
        smtp.login(username, password)  #登陆smtp服务器
        try:
            smtp.sendmail(sender, receiver, msg.as_string())  #发送邮件
            smtp.quit()   #推出smtp邮件服务器
        except Exception as e:
            return f'邮件发送错误:{e}'
        success_log = "'%s'报表已发送到您邮箱,请注意查收!" % self.excel_name
        return success_log   #打印发送邮件成功的信息

if __name__ == '__main__':
    excel_name = 'test.xlsx'  # 导出的excel的名称
    save_path = os.path.join('./', excel_name)  # 导出的excel的存储路径
    to_mail_addr = ['xxx@163.com', 'bbb@126.com']  # 邮件收件人
    cc_mail_addr = []  # 邮件抄送人

    # 查询语句,以及连接的数据库和导出的sheet名,可以添加多个项目,
    sql_items = [
        {
            'sql_query': """select * from app02_user;""",  #这里最好用三引号,这样你SQL如果换行的话也不用加\换行符
            'db': {'host': "localhost", 'user': "root", 'password': "123.com",'database': "db_test", 'port': 3306, 'charset': 'utf8'},  ####数据库连接####
            'sheet_name': 'test'   #excel工作簿中的sheet名
        },
    ]
    print("开始查询数据...")
    data = SelectData(sql_items).select_sql()
    if not data:
        print('没有查到任何数据!')
    print('数据写入excel中...')
    WriteExcel(data,save_path).write_excel()
    print('正在发送邮件...')
    msg = SendMail(save_path,excel_name,to_mail_addr,cc_mail_addr).send_mail()
    print(msg)

注:
拷贝过去,修改以下参数即可运行:
excel_name,save_path,to_mail_addr,cc_mail_addrsql_items中的SQL语句和数据库连接信息即可。
我们查询数据库的时候有是有需要传参数,比如传一个限制时间等。大家就自行研究吧,也可以私信我探讨
特别说明:发邮件的邮箱根据你自己的邮箱情况设定。账户密码以及发件的SMTP服务器、端口等。

如果还有什么不清楚的,也可以私信我,我们交流交流。
新手上路~请老司机勿喷。如果觉得还行对您有帮助,辛苦帮我点个赞 ~谢谢各位啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值