A.互联网状态:Python部署,VSCode部署Python插件,第三库介绍及其下载
检查Python和pip(python自带的库(library)安装器)的安装状态
检查Python的版本(Version):python --version
检查pip的版本:pip --version
安装Python 3
安装python3.9.7的windows版:www.python.org/ftp/python/…
安装本项目所需的Python库
本项目所需的第三方库如下:
import xlwt
import pymysql
import time
import smtplib
import imaplib
import email
import pandas as pd
#额外下载openpyxl
除Python自带的库之外,我们都需要来亲自安装,安装方法:
- 需要鼠标右击任务栏开始键位置,选择Windows终端(管理员)
- 除了pymysql之外,第三方库在Windows终端(管理员)的安装命令如下:
pip install xlwt
pip install cryptography
pip install smtplib
pip install openpyxl
pip install pandas
pip install imaplib
- 对于pymysql来说,安装方法如下(系统需要安装完visual c++ 9.0,并且安装cryptography第三方库):
- a. 下载pymysql安装包,下载地址:github.com/PyMySQL/PyM…
- b. 将压缩包进行解压,在命令行中切换到解压文件所在的位置,运行python setup.py install,最后会出现Finished dependencies...
- c. 运行python,输入import pymysql,验证是否安装成功。
B.互联网状态:云服务器MySQL数据库及表结构介绍
云服务器环境:基于Linux的CentOS 7,数据库使用的时候需要指明下列元素:
- host = '106.54.138.175'(数据库所在的云服务器地址)
- user = 'chinamobile'(数据库用户名)
- pwd = 'cmcc123456'(数据库密码)
- port = 3306
- db = 'chinamobile'
在此基础上,你可以选择利用宝塔面板进行数据库的安装,也可以利用Docker的MySQL镜像进行安装
本次测试用例的MySQL版本:8,在这里,具体的安装细节我们就不展示了,想学的可以在网上百度一下学学,这个不是难点
下面列举在宝塔界面下我们的数据库配置:
为了保障客户的隐私,所有测试表中的手机号码都是随机跑出来的
测试表数据如上图所示,表结构为3列servnumber(手机号码),countyname(号码归属区县),zdkh(重点客户标识)
C.互联网状态:互联网邮件协议及其配置接口介绍
想要利用python来实现邮件服务器内邮件的读取和发送,那就必须要了解邮件的相关协议
那么什么是SMTP和IMAP呢?POP3请自行百度!
SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。\
SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器
在本项目中,SMTP用来登录邮箱发送邮件的,需要指明下列元素:
- mailhost(邮件服务器的地址,例如smtp.139.com)
- username(自己本机的邮箱地址)
- password(自己本机的邮箱密码)
- port(邮件服务器传输端口)
IMAP全称是Internet Mail Access Protocol,即交互式邮件存取协议,它是跟POP3类似邮件访问标准协议之一。
不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。
在本项目中,IMAP用来接收别人发给自己的邮件的,需要指明下列元素:
- mailhost(邮件服务器的地址,例如smtp.139.com)
- username(自己本机的邮箱地址)
- password(自己本机的邮箱密码)
- port(邮件服务器传输端口)
- mailfrom(邮件来源者)
D.互联网状态:项目内声明的函数介绍及其解释
将源代码取消展开如下(展示结构):
代码量在280行左右,体积不大,得益于Python广泛的开源第三方库,才能写这么少!
下面针对每个函数进行解释:
judgefrom函数:负责判断邮件来源
这个函数是自己写的,目的很简单,判断今天的邮件来源是否为客服部,如果是对应邮箱返回整数1,否则整数0
外部输入参数:judgemailfrom,字符串(string),待判断的邮箱字符串
def judgefrom(judgemailfrom):
#判断今天的邮件来源是否为客服部
if (judgemailfrom=="mickeywang98@139.com"):
return 1
else:
return 0
judgedate函数:负责判断邮件附件日期和命名格式
同样的,逻辑和上面差不多,time.strftime函数负责以时间元组,返回以可读字符串表示的当地时间,格式由参数 format 决定,函数格式time.strftime(format[, t])
外部输入参数:filename,字符串(string),待判断的邮箱附件文件名带后缀
def judgedate(filename):
# 并且邮件来自本日
# 格式符合"kefushuju_"+当前时间
if (filename=="kefushuju_" + time.strftime("%Y-%m-%d")+'.xlsx') or (filename=="kefushuju_" + time.strftime("%Y-%m-%d")+'.xls'):
return 1
else:
return 0
excel_one_line_to_list函数:将excel第一列转换为数组list
这里用到了pandas的read_excel函数,header=None是表示filename这个xlsx文件没有表头,不需要跳过第一行读取数据
外部输入参数:filename,字符串(string),待判断的邮箱附件文件名带后缀
str(filename)是强制转换为字符串,写法类似于C语言的强制转换函数
def excel_one_line_to_list(filename):
#将xls第一列的servnumber处理成整形数组result
df = pd.read_excel(filename,header=None) # 读取项目名称列,打开同级目录下的文件
df_li = df.values.tolist()
result = []
for s_li in df_li:
result.append(s_li[0])
print(result)
return result
parseHeader函数:解析邮件头部
在这里,Python 3不需要进行编码(encode)统一码(unicode)操作,原函数被我修改了一下,该函数在getMail中被使用
email.utils.parseaddr(address)是模块中专门用来解析邮件地址的函数
外部输入参数:message,类型为email.message,在邮件包中的核心类是消息类message,从email.message模块导入。它是为电子邮件对象模型的基类。消息提供的核心功能,用于设置和查询报头字段,以及用于访问消息体
def parseHeader(message):
#解析邮件头部
subject = message.get('subject')
h = email.header.Header(subject)
dh = email.header.decode_header(h)
#subject = unicode(dh[0][0], dh[0][1]).encode('gb2312')
subject = (dh[0][0], dh[0][1])
# 主题
print (subject)
print ("</br>")
# 发件人
print ("From:"+ email.utils.parseaddr(message.get('from'))[1])
print ("</br>")
# 收件人
print ("To:" + email.utils.parseaddr(message.get('to'))[1])
print ("</br>")
# 抄送人
print ("Cc:"+ email.utils.parseaddr(message.get_all('cc'))[1])
parseBody函数:负责解析邮件内容
该函数在getMail中被使用
外部输入参数:message,类型为email.message
multipart代指数据块,str(fname).split("'")[1]将fname强制转为str后利用'符号将字符串分割为多个字符串数组,取出数组中的第二个值即为文件名(fname的字符串格式为b'文件名')
def parseBody(message):
#解析邮件内容
# 循环信件中的每一个mime的数据块
for part in message.walk():
# 这里要判断是否是multipart,是的话,里面的数据是一个message 列表
if not part.is_multipart():
charset = part.get_charset()
# print 'charset: ', charset
contenttype = part.get_content_type()
# print 'content-type', contenttype
name = part.get_param("name") #如果是附件,这里就会取出附件的文件名
if name:#在这里额外添加中国移动的条件
# 有附件
# 下面的三行代码只是为了解码像 =?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名
fh = email.header.Header(name)
fdh = email.header.decode_header(fh)
fname = fdh[0][0]
print ('附件名:',fname)
#解码出附件数据,然后存储到文件中
attach_data = part.get_payload(decode=True)
try:
f = open(fname, 'wb') #注意一定要用wb来打开文件,因为附件一般都是二进制文件
except:
print ("附件名有非法字符,自动换一个")
f = open('kefushuju_'+time.strftime("%Y-%m-%d")+'.xlsx', 'wb')
f.write(attach_data)
f.close()
else:
#不是附件,是文本内容
print (part.get_payload(decode=True)) # 解码出文本内容,直接输出来就可以了。
# pass
# print '+'*60 # 用来区别各个部分的输出
return str(fname).split("'")[1]
getMail函数:获得邮件内容(文本&附件)
调用上面声明的parseBody和parseHeader函数,利用imap协议来建立从服务器收取邮件的链接,建立serv连接后利用search来寻找邮箱名
外部输入参数:host, username, password, port, mailfrom,类型为字符串(string),分别为收信服务器地址,邮箱,邮箱密码,服务端口,邮箱发信人
def getMail(host, username, password, port, mailfrom):
#global fn
try:
serv = imaplib.IMAP4_SSL(host, port)
except Exception as e:
serv = imaplib.IMAP4(host, port)
serv.login(username, password)
serv.select()
# 搜索邮件内容
typ, data = serv.search(None, '(FROM "' + mailfrom + '")')
#调用中国移动邮件来源判断
if judgefrom(mailfrom)==1:
x=1
else:
return
count = 1
pcount = 1
for num in data[0].split()[::-1]:
typ, data = serv.fetch(num, '(RFC822)')
text = data[0][1]
message = email.message_from_bytes(text) # 转换为email.message对象
parseHeader(message)
print ("</br>")
f=parseBody(message) #返回值是为了把文件名返回主函数
if f.strip()!='':
fn=f
pcount += 1
if pcount > count:
break
serv.close()
serv.logout()
return fn#返回值是为了把文件名返回主函数
export函数:连接数据库,匹配手机号信息,写入xls
建立数据库连接实例,利用SQL拼接的方式逐条查找,逐行逐列写入xls即可
外部输入参数:servnumber,类型为数组列表(list),传入手机号信息
def export(servnumber):
#数据库连接
conn = pymysql.connect(db=db, user=user,password=pwd, host=host, port=port)#这个链接的配置
cursor = conn.cursor()#链接数据库得到的实例
result=()
counts=0
sql = 'select servnumber,countyname,zdkh from zdkh_test '
print(servnumber)
for num in servnumber:
cursor.execute(sql + "where servnumber='" + str(num) + "';") #执行sql语句
result = cursor.fetchall() + result #返回值是多个元组,即返回多个行记录
counts = cursor.rowcount + counts #记录这个sql执行完毕是多少行
print("Select " + str(counts) + " Records")
# cursor.scroll(0, mode='relative')
fields = cursor.description # 数据表的标题
workbook = xlwt.Workbook(encoding='utf-8') # 创建excel文档
# 根据sheet_name创建excel文档的sheet
sheet = workbook.add_sheet(sheet_name, cell_overwrite_ok=True)
# 写入数据表的文件头
for field in range(0, len(fields)):
sheet.write(0, field, fields[field][0])
# 逐行逐列的添加数据
for row in range(1, len(result) + 1):
for col in range(0, len(fields)):
sheet.write(row, col, u'%s' % result[row-1][col])
workbook.save(out_path) # 按照out_path的格式和路径保存excel表格
return counts
send_email函数:发送邮件
外部输入参数:count,类型为整数(int),值为遍历数据库中查找统计的条数
def send_email(count):
# ----这是文字部分-----
content = '''Dear 客服部, \n附件是每日统计情况,请查收!\n总计结果数位:''' + str(count)
part = MIMEText(content, 'plain', 'utf-8')
msg.attach(part)
if count > 0:
#这是附件部分
# xls类型附件
file_name = 'C:/Users/Lenovo/Desktop/PYOUT/' + filename
part = MIMEText(open(file_name, 'rb').read(), 'base64', 'gb2312')
part["Content-Type"] = 'application/octet-stream'
basename = os.path.basename(file_name)
# part["Content-Disposition"] = 'attachment; filename=%s' % basename.encode('utf-8')
part['Content-Disposition'] = 'attachment; filename=%s' % basename
# part.add_header('Content-Disposition', 'attachment', filename=('utf-8', basename))
msg.attach(part)
#s = smtplib.SMTP_SSL('smtp.chinamobile.com', 465) #连接smtp邮件服务器
s = smtplib.SMTP_SSL('smtp.139.com', 465) #连接smtp邮件服务器
s.login(_user, _pwd)
#s.sendmail(_user, areceiver.split(',') + acc.split(','), msg.as_string()) # send mail
s.sendmail(_user, areceiver, msg.as_string()) # send mail
print("Email send successfully")
s.close()
else:
print("nothing to send!")
main函数:负责调用上述子程序实现
声明各种变量,调用子程序完成整个功能模块
判断文件的日期是否为当天,如果不是的话,后面有个if会拒绝运行数据库查询语句模块和邮件发送模块
#####################主程序环节########################
##########################运行前所有的变量配置和msg配置###########################
# 连接数据库的参数:主机,用户,密码,端口及数据库名称
host = '106.54.138.175'
user = 'chinamobile'
pwd = 'cmcc123456'
port = 3306
db = 'chinamobile'
# 变量声明
sheet_name = 'report' + time.strftime("%Y-%m-%d")
filename = 'report_' + time.strftime("%Y-%m-%d" + "-" + "%H%M%S") + '.xls'
out_path = "C:/Users/Lenovo/Desktop/PYOUT/report_" + \
time.strftime("%Y-%m-%d" + "-" + "%H%M%S") + \
".xls" # 路径文件名使用日期时间来命名,但是文件命名不支持冒号:所以去掉冒号
cur_path = 'C:/Users/Lenovo/Desktop/PYOUT'
print(out_path)
#workbook = xlwt.Workbook(encoding='utf-8')
#sheet = workbook.add_sheet(sheet_name, cell_overwrite_ok=True)
# workbook.save(out_path)
#本机邮箱用户名密码
_user = "mickeywang1998@139.com"
_pwd = "Wcq980220"
areceiver = "mickeywang98@139.com"
#接收者
#areceiver = "mickeywang1998@139.com"
#抄送
acc = ""
#发送本机的历史邮件来源
#mailfrom = "111@139.com"
mailfrom = "mickeywang98@139.com"
#如名字所示Multipart就是多个部分
msg = MIMEMultipart()
msg["Subject"] = u'[Data Select_' + time.strftime("%Y-%m-%d") + u']'
msg["From"] = _user
msg["To"] = areceiver
msg["Cc"] = acc
#sendhost = "imap.chinamobile.com"
sendhost = "imap.139.com"
# "pop.mail_serv.com"
########################调用写好的子程序实现程序功能##########################
#getMail里面调用解析邮件头和邮件文件,获得邮件附件,并将邮件附件路径写入字符串
mainfilename=getMail(sendhost, _user, _pwd, 993, mailfrom)
print(mainfilename)
print(mainfilename)
print(mainfilename)
print(mainfilename)
print(mainfilename)
#将收件附件当中的servnumber读到数组中,准备链接数据库进行SQL匹配获取
servnumber=excel_one_line_to_list(mainfilename)
if judgedate(mainfilename)==1:
#链接数据库,获取数据,写入xlsx
countnum=export(servnumber)
#发送邮件
send_email(countnum)
print("Running successfully!!!")
E.互联网状态:在Windows环境下定时运行脚本
如何将Python的py文件打包成Windows的exe文件
首先,要对写好的python程序进行编译和打包,我们需要安装pyinstaller库,总不能每次都开着编辑器,看着源码跑吧
安装完成之后,我们进行编译,打开python代码所在文件夹
点击红色位置,输入cmd,按下回车enter
输入下面的代码,回车enter,等待一分钟左右,在这个目录下面会出dist文件夹
pyinstaller --onefile --nowindowed --icon="C:\Users\Lenovo\Desktop\PYTEST\cmcc.ico" cmcc_sendemail.py
而这个exe的图标就是命令里面的cmcc.ico
如何实现定时运行exe程序
类似linux中的脚本sh,在windows中我们也有对应的bat脚本
我们可以编写脚本来完成以下动作,每日定时12:00检查邮件服务器有没有客服部的邮件,取数原路返回对应的邮件
新建txt,敲完下面代码,改后缀为bat
@echo off
SCHTASKS /Create /TN sendemail /TR C:\Users\Lenovo\Desktop\PYTEST\dist\cmcc_sendemail.exe /SC DAILY /ST 02:02
pause
代码什么意思呢?
- /create表示创建
- /tn表示创建的任务叫什么名字
- /tr引号表示具体要执行的路径
- /sc表示执行的频率,once就是执行一次
- /st表示开始执行的时间
运行bat显示下面图片(之前我存在同名进程,进行覆盖)
之后只要你的windows不关机到了2:02,就会运行对应的命令!!!大功告成!!!