|
| 1 | +# 天气提醒脚本 |
| 2 | + |
| 3 | +我讨厌下雨天,尤其是出门却没带伞的下雨天。每到这个时候,就特羡慕大头儿子,“人家有伞,我有大头”。。。既然没有大头儿子的天赋异禀,就只能老老实实地带伞了。 |
| 4 | + |
| 5 | +蛋,总是忘了带肿么破!!! |
| 6 | + |
| 7 | +在多次被北京的大雨拍在路上之后,我痛定思痛,决定要想个法子解决忘带伞这一世纪难题。。。 |
| 8 | + |
| 9 | +其实这个问题很好解决嘛,早晨出门前看下天气预报不就行了。对于像我这种每天能够早早起床、舒展一会儿身体、做一顿营养早餐、看一个小时书、在上班路上欣赏北京美景的人来说so easy。 |
| 10 | + |
| 11 | +才怪。 |
| 12 | + |
| 13 | +每天睡的比猪晚、起的比猪早,早晨急忙爬起来刷个牙洗个脸,连个饭都吃不上就要去挤地铁,这还天天迟到呢!哪还能想起来去看天气预报啊!!! |
| 14 | + |
| 15 | +主动去看天气预报这个方案对我来基本无解。。。 |
| 16 | + |
| 17 | +那,就被动好了,让基友在我需要带伞的时候,主动提醒我一下吧。 |
| 18 | + |
| 19 | +好,祭出基友之友--Python!!! |
| 20 | + |
| 21 | +我想让python做以下事情: |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | +所以,要实现以下三部分: |
| 26 | + |
| 27 | +1. 爬取天气数据 |
| 28 | +2. 判断是否有雨 |
| 29 | +3. 发送提醒 |
| 30 | + |
| 31 | +嗯,开搞。 |
| 32 | + |
| 33 | +#### 爬天气预报数据 |
| 34 | +先找个靠谱的天气预报网站,看了一圈,感觉这个[中国天气预报](http://www.weather.com.cn/weather/101010100.shtml)挺靠谱的,毕竟敢用“中国”命名呢。下图就是目标数据了: |
| 35 | + |
| 36 | + |
| 37 | + |
| 38 | +打开浏览器控制台,找到数据在html中的位置: |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +可以看到,7天的天气数据位于 id="7d"的div标签 -> ul标签 -> li标签 中。 |
| 43 | + |
| 44 | +再看看li中的具体结构: |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | + |
| 49 | +* 日期位于 li标签 -> h1标签 中; |
| 50 | +* 天气位于 li标签 -> class="wea"的p标签 中; |
| 51 | +* 最高温度位于 li标签 -> class="tem"的p标签 -> span标签 中; |
| 52 | +* 最低温度位于 li标签 -> class="tem"的p标签 -> i标签 中。 |
| 53 | + |
| 54 | +数据找好了,开始爬数据出来。鉴于爬数据的逻辑简单,直接用urllib2和Beautifulsoup来做。 |
| 55 | + |
| 56 | +``` |
| 57 | +# 爬取7天内的天气数据 |
| 58 | +from bs4 import BeautifulSoup |
| 59 | +import urllib2 |
| 60 | +def fetch_weather_datas(): |
| 61 | + # 请求页面数据 |
| 62 | + response = urllib2.urlopen(url='http://www.weather.com.cn/weather/101010100.shtml') |
| 63 | + body = response.read() |
| 64 | +
|
| 65 | + # 用BeautifulSoup解析,取出7天的天气数据 |
| 66 | + soup = BeautifulSoup(body) |
| 67 | + tags = soup.select('#7d > ul > li') |
| 68 | +
|
| 69 | + return ['%s\t%s\t%s\t%s' % # 对七天的数据分别解析,将解析后的每天的数据拼接成“日期+天气+最高气温+最低气温”的字符串,\t分隔 |
| 70 | + ( |
| 71 | + tag.select('h1')[0].string, # 取时间数据 |
| 72 | + tag.select('.wea')[0]['title'], # 取天气数据 |
| 73 | + tag.select('.tem > span')[0].string, # 取最高气温 |
| 74 | + tag.select('.tem > i')[0].string # 取最低气温 |
| 75 | + ) |
| 76 | + for tag in tags] # 返回结果为List |
| 77 | +``` |
| 78 | + |
| 79 | +#### 今天是否有雨? |
| 80 | +拿到天气数据之后,要看下今天的天气如何,是否需要提醒我带伞。 |
| 81 | + |
| 82 | +``` |
| 83 | +# 传入爬到的天气数据,判断今天是否是雨天 |
| 84 | +def is_rainy_day(weather_datas): |
| 85 | + return '雨' in weather_datas[0] # weather_datas[0]为今天的数据 |
| 86 | +``` |
| 87 | + |
| 88 | +#### 发送提醒 |
| 89 | +因为我手机上的邮件客户端始终在后台开启,选择用邮件的方式来做提醒比较合适,所以使用了Python自带的邮件发送工具:smtplib。 |
| 90 | +需要有一个发送提醒邮件的邮箱账号,我用的是新浪的邮箱。 |
| 91 | + |
| 92 | +``` |
| 93 | +# 发送邮件 |
| 94 | +import smtplib |
| 95 | +from email.mime.text import MIMEText |
| 96 | +from email.header import Header |
| 97 | +def send_mail(receivers, datas): |
| 98 | + mail_host = 'smtp.sina.com' # 设置服务器,不同的邮箱对应的smtp服务器地址不同 |
| 99 | + mail_user = 'username' # 用户名,发送邮件的邮箱账号的用户名 |
| 100 | + mail_pass = 'password' # 密码,发送邮件的邮箱密码 |
| 101 | +
|
| 102 | + # 定义邮件内容 |
| 103 | + message = MIMEText('\n'.join(datas), 'plain', 'utf-8') # 邮件内容为爬取到的近7天天气数据 |
| 104 | + message['From'] = Header(mail_user) # 邮件的发送方 |
| 105 | + message['To'] = Header(','.join(receivers), 'utf-8') # 邮件的接受方,逗号分隔 |
| 106 | + message['Subject'] = Header('天气提醒', 'utf-8') # 邮件主题 |
| 107 | +
|
| 108 | + try: |
| 109 | + smtpObj = smtplib.SMTP() |
| 110 | + smtpObj.connect(mail_host, 25) # 连接服务器, 25 为新浪邮箱 SMTP 端口号 |
| 111 | + log('连接服务器成功..') |
| 112 | + smtpObj.login(mail_user, mail_pass) # 登录服务器 |
| 113 | + log('登录邮箱服务器成功..') |
| 114 | + smtpObj.sendmail(from_addr=mail_user, to_addrs=receivers, msg=message.as_string()) # 发送邮件 |
| 115 | + log('邮件发送成功..') |
| 116 | + except smtplib.SMTPException as e: |
| 117 | + log('无法发送邮件...' + e.message) |
| 118 | +
|
| 119 | +
|
| 120 | +# 日志打印 |
| 121 | +import time |
| 122 | +def log(msg): |
| 123 | + timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) |
| 124 | + print '[%s] %s' % (timestamp, msg) |
| 125 | +``` |
| 126 | + |
| 127 | +#### 整合 |
| 128 | +将上边编写完成的方法按下边的方式整合到一起,就是一个能够发送天气提醒的脚本了: |
| 129 | + |
| 130 | +``` |
| 131 | +try: |
| 132 | + weather_datas = fetch_weather_datas() # 爬取天气数据 |
| 133 | + if is_rainy_day(weather_datas): # 今天是否是雨天 |
| 134 | + send_mail('[email protected]', weather_datas) # 发送天气数据到目标邮箱 |
| 135 | + else: |
| 136 | + log('今天天气良好..') |
| 137 | +except: |
| 138 | + log('出错..') |
| 139 | +``` |
| 140 | + |
| 141 | +#### 定时执行 |
| 142 | +写完脚本后,我希望这个脚本能在每天早晨6点30分执行,这样我就能在醒来的第一时间就能看到提醒邮件并带上雨伞了。 |
| 143 | + |
| 144 | +首先需要一个能联网的服务器,将脚本放在服务器中。 |
| 145 | + |
| 146 | +然后,用crontab来做定时的任务(linux环境)。执行: |
| 147 | + |
| 148 | +`crontab -e` |
| 149 | + |
| 150 | +此时会进入进入vim界面,进入编辑模式,输入: |
| 151 | + |
| 152 | +`30 6 * * * /usr/bin/python xxxx/weather.py >> run.log` |
| 153 | + |
| 154 | +保存,此时定时任务就跑起来了,日志记录在run.log文件中。 |
| 155 | + |
| 156 | +> 具体的cron表达式语法在网上有很多教程,就不细说了。 |
| 157 | +
|
| 158 | +#### 完成 |
| 159 | +不必再羡慕大头儿子了!虽然他有大头,但是我有伞啊~ |
0 commit comments