如果要求你進行一個表數據的導出,如果使用shell的話,很容易做到,即執行一下 select 語句就可以拿到返回結果了!
如下:
/usr/bin/mysql -u"${username}" -p"${password}" --host=${host} -D"${database}" < ${sql_script_path} > ${export_data_full_path1};
如上執行完成之后,數據就被導出到 export_data_full_path1 指定的文件位置去了。
如果想要使用 excel 格式來打開,有一個很簡單的方法,即把后綴名命名為: .xls 就可以了。唯一的缺點是,此時你可能看到一個提示,即:文件名后綴與具體的格式不匹配等等!但是你仍然可以正常打開!
但是對於有中文一類的導出操作,則又是,另一番景象了!不過我們可以通過一個簡單的編碼轉換來解決這個問題!
iconv -futf8 -tgb2312 -o ${export_data_full_path1} ${export_data_full_path1};
轉換之后,即使有中文也能正常查看了!
至於使用 shell 進行發送郵件,則也是簡單的一比!
echo "yesterday report infomation, FYI ." | mail -s "$yesterday_format report" -a ${export_data_full_path1} ${mail_receivers}
完整的匯總數據sql 加 發送郵件 shell , 區區幾行代碼如下:
#!/bin/bash sql_script_path="/scripts/report/report.sql"; # data sync target configs host="127.0.0.1"; username="test"; password='123456'; database='test'; export_data_path_prefix="/data/report/export_datas"; mail_receivers="test@163.com"; yesterday_format=`date '+%Y-%m-%d' -d '-1 day'`; export_data_full_path1="${export_data_path_prefix}/${yesterday_format}-Report.xls"; /usr/bin/mysql -u"${username}" -p"${password}" --host=${host} -D"${database}" < ${sql_script_path} > ${export_data_full_path1}; iconv -futf8 -tgb2312 -o ${export_data_full_path1} ${export_data_full_path1}; # todo: send mail begin echo '$yesterday_format report infomation, FYI .' | mail -s "$yesterday_format report" -a ${export_data_full_path1} ${mail_receivers} echo `date '+%Y-%m-%d %H:%I:%S'` "over!"
如上,完成了使用 shell 進行匯總數據,並導出 excel 發送郵件的功能了!優缺點如下:
優點: 1. 簡單!
缺點: 1. 不能支持復雜格式的指定! 2. 需要安裝 mysql-client 包!
所以,針對上面問題,尤其是不支持復雜格式的指定問題,注定我們需要一個更完善的方式來實現!即使用 python 等一類強大語言支持!
同樣,我們對這類操作有兩大要求: 1. 簡單; 2. 支持復雜操作; 很明顯,python 在這種場景下很得心應手!
我們先來看一下完整實現:
#!/usr/bin/env python # -*- coding: utf-8 -*- # need install components: openpyxl, pymysql from openpyxl import Workbook import pymysql import time import sys from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.header import Header from email.utils import formataddr import smtplib import random class MysqlClient: # create connection to mysql def __init__(self, db_host, user, password, database, port=10000, authMechanism="PLAIN"): self.conn = pymysql.connect(host=db_host, port=port, user=user, password=password, database=database, ) def query(self, sql): with self.conn.cursor() as cursor: cursor.execute(sql) return cursor.fetchall() def close(self): self.conn.close() class MailClient: # initial account info def __init__(self, sender_account, sender_pass, report_date): self.sender_account = sender_account self.sender_pass = sender_pass self.report_date = report_date def send_mail(self, receivers, subject, msg_content, xls_file_path): try: msg = MIMEMultipart() attach = MIMEApplication(open(xls_file_path, 'rb').read()) attach.add_header('Content-Disposition', 'attachment', filename=self.report_date + '-Reprot.xlsx') msg.attach(attach) body = MIMEText(msg_content, 'html', 'utf-8') msg.attach(body) msg['From'] = self.sender_account msg['To'] = ','.join(receivers) msg['Subject'] = Header(subject, 'utf-8') server = smtplib.SMTP_SSL("smtp.exmail.qq.com", 465) server.login(mail_sender, sender_pass) server.sendmail(mail_sender, receivers, msg.as_string()) server.quit() print(self.report_date + '-----success') except Exception as e: print(self.report_date + '-----failed') print(e) def create_xsls(info_report, xls_file_path): mysql_client = MysqlClient(db_host='127.0.0.1', port=3306, user='test', password='test', database='testdb') wb = Workbook() inx_rep = 0 for report in info_report: result = mysql_client.query(report.get('report_sql')) if inx_rep == 0: ws = wb.worksheets[0] ws.title = report.get('rep_name') else: ws = wb.create_sheet(title=report.get('rep_name')) titleidx = 0 titlenames = report.get('rep_title') for titlename in titlenames.split(","): if chr(ord('A') + titleidx) <= 'Z': title_name = chr(ord('A') + titleidx) else: title_name = "A" + chr(ord('A') + titleidx - 26) ws[title_name + "1"] = titlename titleidx = titleidx + 1 row_num = 2 for line in result: titleidx = 0 for titlename in titlenames.split(","): if chr(ord('A') + titleidx) <= 'Z': title_name = chr(ord('A') + titleidx) else: title_name = "A" + chr(ord('A') + titleidx - 26) ws[title_name + str(row_num)] = line[titleidx] titleidx = titleidx + 1 row_num = row_num + 1 inx_rep = inx_rep + 1 wb.save(xls_file_path) def main(argv): if(argv[1] == 'user_reg'): test_sql = '''SELECT DATE(create_time) AS 日期, user_flag AS 用戶類型, FROM t_user s WHERE create_time>='2019-01-01' AND repay_time<=DATE_ADD(NOW(),INTERVAL 1 DAY) GROUP BY DATE(create_time),user_flag LIMIT 1000; ''' info_report = [{"rep_name":"測試工單","rep_title":"日期,用戶類型,注冊來源","report_sql":test_sql}] receivers = ['test2@163.com'] else: pass; report_date = time.strftime('%Y%m%d', time.localtime()) rep_rand = random.randint(100, 999) xls_file_path = '/mnt/data/report/data/' + argv[1] + '-' + report_date + '-Reprot' + str(rep_rand) + '.xlsx'; create_xsls(info_report, xls_file_path) mail_client = MailClient(sender_account='test@163.cn', sender_pass='1234567', report_date=report_date) mail_client.send_mail(receivers, subject='測試主題', msg_content='測試body', xls_file_path=xls_file_path) if __name__ == "__main__": main(sys.argv)
如上代碼,代碼本身很短,實際邏輯也很簡單!
1. 定義好各種參數,如 文件名,數據庫連接參數信息,郵件主題等信息;
2. 調用mysql模塊進行數據查詢;
3. 調用 workbook excel 模塊進行 excel 文件內容填充;
4. 調用郵件發送模塊進行郵件發送,包括附件;
最后,對於報表類,處理,我們一般要求每天進行匯總,對於這類請求,我們可以簡單地使用 crontab 進行定時調度實現即可!
其中,稍微有幾點要注意下的就是:
1. 必須先安裝 openpyxl, pymysql 兩個基礎模塊的依賴;
pip install openpyxl pymysql
2. 進行表單數據填充時,注意標題與數據的對位問題;
3. smtp 默認是25端口進行郵件發送,但是在某些情況無法使用 25 端口,如阿里雲服務器環境,所以可以使用465端口進行發送;
4. 當需要進行附件的發送時,需要使用 MIMEMultipart 進行封裝;
雖然也有些事項注意起來讓我們感覺很煩,但是已經很簡單了,這也 python 會這么流行的原因吧!
可作參考!