我討厭下雨天,尤其是出門卻沒帶傘的下雨天。每到這個時候,就特羨慕大頭兒子,“人家有傘,我有大頭”。。。既然沒有大頭兒子的天賦異稟,就只能老老實實地帶傘了。
蛋,總是忘了帶腫么破!!!
在多次被北京的大雨拍在路上之后,我痛定思痛,決定要想個法子解決忘帶傘這一世紀難題。。。
其實這個問題很好解決嘛,早晨出門前看下天氣預報不就行了。對于像我這種每天能夠早早起床、舒展一會兒身體、做一頓營養早餐、看一個小時書、在上班路上欣賞北京美景的人來說so easy。
才怪。
每天睡的比豬晚、起的比豬早,早晨急忙爬起來刷個牙洗個臉,連個飯都吃不上就要去擠地鐵,這還天天遲到呢!哪還能想起來去看天氣預報啊!!!
主動去看天氣預報這個方案對我來基本無解。。。
那,就被動好了,讓基友在我需要帶傘的時候,主動提醒我一下吧。
好,祭出基友之友--Python!!!
我想讓python做以下事情:
所以,要實現以下三部分:
- 爬取天氣數據
- 判斷是否有雨
- 發送提醒
嗯,開搞。
爬天氣預報數據
先找個靠譜的天氣預報網站,看了一圈,感覺這個中國天氣預報挺靠譜的,畢竟敢用“中國”命名呢。下圖就是目標數據了:
打開瀏覽器控制臺,找到數據在html中的位置:
可以看到,7天的天氣數據位于 id="7d"的div標簽 -> ul標簽 -> li標簽 中。
再看看li中的具體結構:
- 日期位于 li標簽 -> h1標簽 中;
- 天氣位于 li標簽 ->** class="wea"**的p標簽 中;
- 最高溫度位于 li標簽 -> class="tem"的p標簽 ->span標簽 中;
- 最低溫度位于 li標簽 -> class="tem"的p標簽 -> i標簽 中。
數據找好了,開始爬數據出來。鑒于爬數據的邏輯簡單,直接用urllib2和BeautifulSoup來做。
# 爬取7天內的天氣數據
from bs4 import BeautifulSoup
import urllib2
def fetch_weather_datas():
# 請求頁面數據
response = urllib2.urlopen(url='http://www.weather.com.cn/weather/101010100.shtml')
body = response.read()
# 用BeautifulSoup解析,取出7天的天氣數據
soup = BeautifulSoup(body, "lxml")
tags = soup.select('#7d > ul > li')
return ['%s\t%s\t%s\t%s' % # 對七天的數據分別解析,將解析后的每天的數據拼接成“日期+天氣+最高氣溫+最低氣溫”的字符串,\t分隔
(
tag.select('h1')[0].string, # 取時間數據
tag.select('.wea')[0]['title'], # 取天氣數據
tag.select('.tem > span')[0].string, # 取最高氣溫
tag.select('.tem > i')[0].string # 取最低氣溫
)
for tag in tags] # 返回結果為List
今天是否有雨?
拿到天氣數據之后,要看下今天的天氣如何,是否需要提醒我帶傘。
# 傳入爬到的天氣數據,判斷今天是否是雨天
def is_rainy_day(weather_data):
return '雨' in weather_data
發送提醒
因為我手機上的郵件客戶端始終在后臺開啟,選擇用郵件的方式來做提醒比較合適,所以使用了Python自帶的郵件發送工具:smtplib。
需要有一個發送提醒郵件的郵箱賬號,我用的是新浪的郵箱。
# 發送郵件
import smtplib
from email.mime.text import MIMEText
from email.header import Header
def send_mail(receivers, datas):
mail_host = 'smtp.sina.com' # 設置服務器,不同的郵箱對應的smtp服務器地址不同
mail_user = 'username' # 用戶名,發送郵件的郵箱賬號的用戶名
mail_pass = 'password' # 密碼,發送郵件的郵箱密碼
# 定義郵件內容
message = MIMEText('\n'.join(datas), 'plain', 'utf-8') # 郵件內容為爬取到的近7天天氣數據
message['From'] = Header(mail_user) # 郵件的發送方
message['To'] = Header(','.join(receivers), 'utf-8') # 郵件的接受方,逗號分隔
message['Subject'] = Header('天氣提醒', 'utf-8') # 郵件主題
try:
smtpObj = smtplib.SMTP()
smtpObj.connect(mail_host, 25) # 連接服務器, 25 為新浪郵箱 SMTP 端口號
log('連接服務器成功..')
smtpObj.login(mail_user, mail_pass) # 登錄服務器
log('登錄郵箱服務器成功..')
smtpObj.sendmail(from_addr=mail_user, to_addrs=receivers, msg=message.as_string()) # 發送郵件
log('郵件發送成功..')
except smtplib.SMTPException as e:
log('無法發送郵件...' + e.message)
# 日志打印
import time
def log(msg):
timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
print '[%s] %s' % (timestamp, msg)
整合
將上邊編寫完成的方法按下邊的方式整合到一起,就是一個能夠發送天氣提醒的腳本了:
try:
weather_datas = fetch_weather_datas() # 爬取天氣數據
if is_rainy_day(weather_datas[0]): # 今天是否是雨天
send_mail('xxxx@sina.com', weather_datas) # 發送天氣數據到目標郵箱
else:
log('今天天氣良好..')
except:
log('出錯..')
定時執行
寫完腳本后,我希望這個腳本能在每天早晨6點30分執行,這樣我就能在醒來的第一時間就能看到提醒郵件并帶上雨傘了。
首先需要一個能聯網的服務器,將腳本放在服務器中。
然后,用crontab來做定時的任務(linux環境)。執行:
crontab -e
此時會進入vim界面,進入編輯模式,輸入:
30 6 * * * /usr/bin/python xxxx/weather.py >> run.log
保存,此時定時任務就跑起來了,日志記錄在run.log文件中。
具體的cron表達式語法在網上有很多教程,就不細說了。
完成
不必再羨慕大頭兒子了!雖然他有大頭,但是我有傘啊~
Tip
完整的代碼可以看這里。
如有問題,歡迎交流~