最近在摆弄Python和树莓派,故写了个定时发送免费天气预报(邮件)短信通知的Python脚本,通用Linux,也适合树莓派或者Windows系统,为Python3版本,Python2环境下使用的话,则要重新载入sys并设置utf8。
这里提供的是个人使用的单用户单城市版本。
# -*- coding: utf-8 -*-
"""
Spyder Editor
一个适合个人使用的定时发送天气预报短信的Python脚本.
原理,自动发送到你自己的邮箱,然后若邮箱有短信通知功能,就等于实现了短信通知。
一般运营商的邮箱都有这个邮件到达短信通知功能。
若改一改,就可以实现批量群发和多城市查询,甚至可以实现自动发送微信版天气预报通知到指定手机。
可放在树莓派中设置为开机自动运行。
树莓派中使用时,请用python3 XXX.py 方式启动。因为树莓派中python默认是python2。
需自己配置的参数有5个,请自行修改下方程序中对应项目:
fzs='18:18:00' 设置邮件发送的时间,样例中是每天的18点18分发送天气预报邮件
Get_weather_data('北京') 修改对应的城市名称为你需要查询的城市
'[email protected]' 应修改为发送邮件的邮箱,样例中是163邮箱
'[email protected]' 应修改为收取天气预报邮件的邮箱,样例中是139邮箱
"your_mima" 应修改为发送邮件的邮箱对应的发送邮件密码,一般的邮箱同登录密码,但网易163系列邮箱则是授权码,不是登录密码
部分代码实现参考了网络上其他作者的代码,本程序已经调试通过,无bug
修正日志:
20200625,因为数据源对风力的解析结果稍有变化,现配对为最新的风力解析方式
"""
#导入必要模块
import requests
import json
import datetime
import time
import sys
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
#定时任务
def timerFun(sched_Timer):
flag=0
while True:
now=datetime.datetime.now().strftime('%Y-%m-%d
%H:%M')
xcsj=sched_Timer.strftime('%Y-%m-%d
%H:%M')
if now==xcsj:
flag=1
#执行天气预报查询并发送邮件
print('时间一致,开始发送天气预报邮件')
weather_data = Get_weather_data('北京')
weather_forecast_txt, forecast, nr =
Show_weather(weather_data)
if
weather_forecast_txt=='N':
print('查询天气的地址不对,程序终止')
sys.exit()
to_email(weather_forecast_txt,nr)
else:
if
flag==1:
sched_Timer=sched_Timer+datetime.timedelta(days=1)#days=1按天循环,minutes=1按分钟循环,hours=1按小时循环
print('下次比较时间是:'+sched_Timer.strftime('%Y-%m-%d %H:%M'))
flag=0
time.sleep(60)#每60秒检查一次即可
#定义获取天气数据函数
def Get_weather_data(diqu):
print('------天气查询------')
city_name=diqu
url =
'http://wthrcdn.etouch.cn/weather_mini?city=' + city_name
while True:
res=requests.get(url)
try:
res.raise_for_status()
res.encoding = res.apparent_encoding #设置编码
weather_data=res.text
break
except Exception as exc:
print('产生一个故障: %s%s,120秒后重试' % (url,'打开失败'))
time.sleep(120)
# 读取网页数据
weather_dict =
json.loads(weather_data)
return
weather_dict
#定义当天天气输出格式
def Show_weather(weather_data):
weather_dict =
weather_data
if
weather_dict.get('desc') == 'invilad-citykey':
print('你输入的城市有误或未收录天气,请重新输入...')
weather_forecast_txt='N'
forecast='N'
nr='N'
elif
weather_dict.get('desc') == 'OK':
forecast =
weather_dict.get('data').get('forecast')# 算星期几
print('日期:%s' % forecast[1].get('date'))
print('城市:%s' %
weather_dict.get('data').get('city'))
print('天气:%s' % forecast[1].get('type'))
print('温度:%s' %
(weather_dict.get('data').get('wendu') + ''))
print('高温:%s' % forecast[1].get('high'))
print('低温:%s' % forecast[1].get('low'))
print('风级:%s' %
forecast[1].get('fengli').split('[')[2].split(']')[0])
print('风向:%s' %
forecast[1].get('fengxiang'))
weather_forecast_txt = '%s,%s,' \
'%s,' \
'%s-' \
'%s,' \
'风力%s,' \
'当前温度%s,%s天气预报' % \
(
weather_dict.get('data').get('city'),
str((datetime.date.today()+datetime.timedelta(days=1))).replace('-',''),
forecast[1].get('type'),
str(forecast[1].get('low')).replace('低温',''),
forecast[1].get('high').replace('高温',''),
forecast[1].get('fengli').split('[')[2].split(']')[0],
weather_dict.get('data').get('wendu') + '',
weather_dict.get('data').get('city')
)
nr='温馨提示:%s 发送时间:%s' %
(weather_dict.get('data').get('ganmao'),datetime.datetime.now().strftime('%Y-%m-%d
%H:%M:%S'))
return
weather_forecast_txt,forecast,nr
#发送邮件
def to_email(bt,nr):
my_sender='[email protected]' #设置发件人邮箱账号,为了后面易于维护,所以写成了变量
my_user='[email protected]'
#收件人邮箱账号,为了后面易于维护,所以写成了变量,写成运营商的邮箱可以利用邮件到达通知功能实现天气预报短信功能。
def mail():
ret=True
try:
msg=MIMEText(nr,'plain','utf-8')
msg['From']=formataddr(["天气预报",my_sender]) #括号里的对应发件人邮箱昵称、发件人邮箱账号
msg['To']=formataddr(["H",my_user]) #括号里的对应收件人邮箱昵称、收件人邮箱账号
msg['Subject']=bt #邮件的主题,也可以说是标题
server=smtplib.SMTP("smtp.163.com",25) #发件人邮箱中的SMTP服务器,端口是25
server.login(my_sender,"your_mima") #设置163邮箱的smtp授权码,不是163邮箱登录密码。括号中对应的是发件人邮箱账号、邮箱密码
server.sendmail(my_sender,[my_user,],msg.as_string()) #括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
server.quit() #这句是关闭连接的意思
except Exception: #如果try中的语句没有执行,则会执行下面的ret=False
ret=False
return ret
bccs=20#设置报错尝试的次数
js=0#初始化报错计数
while True:
ret=mail()
if ret:
print("邮件发送成功!标题:%s,内容:%s" % (bt,nr))
#如果发送成功则会返回ok,稍等20秒左右就可以收到邮件
break
else:
print("邮件发送失败!30秒后重试") #如果发送失败则会返回filed
js=js+1
if
js<=bccs:
time.sleep(30)
else:
break
#主函数
if __name__=='__main__':
#开机预留启动时间,方便树莓派联网
time.sleep(10)
today =
datetime.date.today()
tomorrow = today +
datetime.timedelta(days=1)
jtrq=today.strftime('%Y-%m-%d')
fzs='18:18:00'#设置邮件发送的时间
jtrq=jtrq+'
'+fzs#设置小时分秒,以后每天这个时候会发送,精确到分钟
if
datetime.datetime.strptime(jtrq,'%Y-%m-%d
%H:%M:%S')>datetime.datetime.now():
sched_Timer=datetime.datetime.strptime(jtrq,'%Y-%m-%d
%H:%M:%S')
else:
sched_Timer=datetime.datetime.strptime(tomorrow.strftime('%Y-%m-%d')+'
'+fzs,'%Y-%m-%d %H:%M:%S')
qdbt='天气预报启动成功,时间:%s' %
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
qdnr='第一次发送时间为:%s' %
sched_Timer
to_email(qdbt,qdnr)
time.sleep(5)
timerFun(sched_Timer)#按天循环