上班的日子老是3點一線,家裏,公司和上班的路徑,對於一個特別懶得我來講,常常遇到上班路上下雨了,而我卻沒帶傘,多麼痛的領悟。最近對python有一種狂熱的學習熱情,寫了4年多的C++代碼,對於python我不能說簡單,可是他作東西確實太快了,現有的第三方資源真的炒雞多,用的我也是不亦樂乎。除了上班忘記帶傘,天天重複性的工做還有不少,好比上下班打卡、每一個禮拜的週報,還有若是有關心的女神,也能夠作定時發送內心話,或者定時提醒等各類服務。有時候想若是有一我的能按時提醒我就行了,這種想法也就停留了那麼幾分鐘就被本身pass掉了,由於別人也可能忘記啊。。。那麼這件事是否是能夠交給程序來作呢!畢竟程序但是會老老實實的作重複性的工做,並且他們樂此不疲。html
上述問題的場景大多都是須要程序在指定時間、或者指定場合提醒咱們該幹什麼了,本篇文章就定時天氣提醒服務來作開篇,講述使用Python怎麼完成這樣一個任務,既然這樣,那咱們就開始構思咱們的程序吧python
看過背景中的需求描述,要實現這個功能,咱們須要解決如下這麼幾個問題:git
一、爬取天氣信息,那麼接下來就產生第二個問題了github
二、動態獲取指定城市天氣web
三、發送天氣信息給指定微信好友數據庫
四、定時觸發爬取動做json
五、怎麼關聯微信帳號小程序
下面咱們將一步一步解決上述幾個問題,並實現咱們的需求windows
解決問題1:瀏覽器
對於使用過爬蟲的同窗來講,爬取天氣信息並不難,以前也瞭解過一些爬取web信息的代碼,簡單的爬蟲無非就是那麼幾步
一、肯定爬取的url,使用瀏覽器打開
二、F12查看網頁佈局信息
三、使用xpath或者bs4進行節點定位
四、拿到頁面信息
五、本身拼接爬取到的信息
六、寫文件、寫數據庫、發送網絡等等
這裏貼下我以前寫的幾個簡單爬蟲:
三、python爬蟲Scrapy(一)-我爬了boss數據,這個應該還有個下篇,後面待續
下面是爬取城市天氣的python方法,須要注意一點的是getWeath接口的參數city_code,這是一個全國城市編碼,每一個城市都是惟一的,這個表格我已經整理成了一個txt文檔,後續放源碼的時候會一併提供。
1 headers = { 2 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", 3 } 4 5 def getWeath(city_code): 6 try: 7 url = f'http://www.weather.com.cn/weather/{city_code}.shtml' 8 resp = requests.get(url, headers = headers) 9 except BaseException as e: 10 print(e) 11 return {} 12 13 resp.encoding = 'utf-8' 14 soup = BeautifulSoup(resp.text, 'html.parser') 15 tagToday = soup.find('p', class_ = "tem") #第一個包含class="tem"的p標籤即爲存放今每天氣數據的標籤 16 try: 17 temperatureHigh = tagToday.span.string #有時候這個最高溫度是不顯示的,此時利用次日的最高溫度代替。 18 except AttributeError: 19 temperatureHigh = tagToday.find_next('p', class_="tem").span.string #獲取次日的最高溫度代替 20 21 temperatureLow = tagToday.i.string #獲取最低溫度 22 weather = soup.find('p', class_ = "wea").string #獲取天氣 23 wind = soup.find('p', class_ = "win") #獲取風力 24 clothes = soup.find('li', class_ = "li3 hot") #穿衣指數 25 26 return {'溫度':f'{temperatureHigh}/{temperatureLow}' 27 , '天氣':weather 28 , '風力':wind.i.string 29 , '穿衣':clothes.a.span.string + ',' + clothes.a.p.string}
上述方法能夠獲取一個城市的天氣信息,並儲存在一個字典中,咱們要發送給好友,還須要對其進行字符串處理,處理代碼以下:
1 def strDic(dic): 2 str_weather = '' 3 for key in dic: 4 str_weather += key + ':' + dic[key] 5 str_weather += '\n' 6 return str_weather
全國城市編碼以下圖所示,每一個城市的編碼都是一個9位的數字組成,獲取天氣信息時是經過指定該編碼進行查詢。
解決問題3:發送消息給好友
解決問題5:怎麼關聯微信帳號,使用wechat_sender庫
咱們本身爬取到的天氣信息怎麼和微信能扯上關係呢,這個時候就要提到我以前寫過的一篇文章微信聊天機器人-存儲好友分享消息,沒有看過的同窗能夠快速瀏覽一遍,簡單來講就是登錄一個web版本的微信帳號,在咱們的電腦上,作這麼一個機器人使用了庫wxpy,要想和這個機器人勾搭上,那咱們就須要請出咱們今天的重磅嘉賓wechat_sender,wechat_sender是基於wxpy和tornado 實現的一個能夠將你的網站,爬蟲,腳本等其餘應用中各類消息(日誌,報警,運行結果等)發送到微信的工具包,有了他咱們的消息就能夠順利的發送到咱們的餓微信帳戶了。
交互流程
如上圖所示,首先使用wxpy登錄微信機器人,固然這個機器人使用的是咱們本身的微信帳號,這裏須要特別注意一點,微信聊天機器人-存儲好友分享消息這篇文章中講述的機器人進入命令狀態是使用的embed()方法,在這裏咱們不能使用該接口了,咱們須要換成上述交互流程的很關鍵的一步,使用listen接口進行監聽,這樣咱們的web工具才能發送消息給機器人,建議仔細閱讀一遍wechat_sender說明文檔,內容很少
登錄微信機器人
爬取到天氣信息之後,使用wechat_sender中的Sender類直接發送消息給微信機器人,下屬代碼中嘗試是用來多種發送消息的方式,代碼中都有詳細註釋,可自行閱讀
1 def sendWeatherMsg(receivers, msg): 2 try: 3 #receivers = [u'拉卡拉', u'證實給他看', u'李靜'] 4 5 #receivers = u'李靜,情繞指尖' 6 7 ''' 8 #發送給指定好友 若是好友不存在 則發送給文件夾傳輸助手 9 Sender(receivers = u'證實給他看').send(msg) 10 Sender(receivers = u'拉卡拉').send(msg) 11 Sender(receivers = u'李靜').send(msg) 12 ''' 13 14 ''' ''' 15 #發送給指定接收的用戶 16 #receivers = u'拉卡拉' 17 #接受者必須是監聽對象的子集 18 sender = Sender(receivers = receivers, token = 'weather_report_123456789') 19 sender.send(msg)#若是沒有指定receivers則發送給文件傳輸助手 20 21 22 ''' 23 receivers = u'李靜,情繞指尖' 24 sender = Sender(receivers = receivers, token = 'weather_report_123456789') 25 26 #有時候好使 有時候很差使 27 sender.send_to('@wss', u'拉卡拉') #消息發送失敗 會默認發送給receivers的第一個用戶 Sender和Listen 28 #sender.send_to(msg, u'證實給他看') 29 ''' 30 31 #測試控制命令 32 ''' 33 receivers = u'拉卡拉' 34 sender = Sender(receivers = receivers, token = 'weather_report_123456789') 35 sender.send('@wss')#文若是沒有指定receivers則發送給文件傳輸助手件傳輸助手 36 ''' 37 38 except BaseException as e: 39 print(e)
登錄微信機器人微信聊天機器人-存儲好友分享消息已經講過,有不懂的同窗能夠回頭看下,下邊代碼中第12行很是關鍵,這一行就是用來監聽外部程序發送消息的。
1 bot = Bot(cache_path = True) 2 3 receivers = [] 4 receivers.append(bot.file_helper) 5 receivers.append(bot.friends().search('拉卡拉')[0]) 6 receivers.append(ensure_one(bot.friends().search('李靜', city='西安')))#有可能搜索出多個結果 7 receivers.append(bot.friends().search('證實給他看')[0]) 8 receivers.append(bot.friends().search('媽')[0]) 9 10 print(receivers) 11 12 listen(bot, receivers = receivers, token = 'weather_report_123456789') #關鍵一步
解決問題2,根據配置的城市名稱動態獲取城市編碼,而後請求數據
因爲沒有接口能夠直接獲取城市編碼,所以這裏咱們本身封裝了一個類來進行管理城市名稱和城市編碼,拉取城市天氣時,只要輸入城市名稱,那麼城市編碼便可經過該類獲取到,具體代碼以下
1 import os 2 3 class City(object): 4 def __init__(self): 5 self.city = {} 6 7 def load(self, file): 8 if os.path.exists(file): 9 with open(file, 'r', encoding = 'utf-8') as f: 10 cityInfo = f.readline().strip('\n') 11 while cityInfo: 12 datas = cityInfo.split(':') 13 self.city[datas[0]] = datas[1] 14 cityInfo = f.readline().strip('\n') 15 16 def find_code(self, city_name):#根據城市名稱,查找城市吧編碼 17 if city_name in self.city: 18 return self.city[city_name] 19 return ''
解決問題4:定時發送任務
咱們的需求是每日定時拉取天氣信息,併發送給指定好友,python有一個APScheduler庫,支持定時任務,具體使用比較負責,我也沒有仔細研究,這裏咱們只是須要使用一個定時任務,其餘不作介紹,有興趣的同窗可自行研究。
在研究定時任務的過程當中,一直沒有找到BackgroundScheduler類add_job時,回調函數怎麼傳遞參數,所以這裏我封裝了一個類,讓定時任務和任務回調處於一個域內,這樣參數就能夠放在類的成員變量未知,不須要傳遞了,哪位大神若是會次操做,能夠評論區指出,很是感謝
1 class MyJob(object): 2 def __sendWeatherMsg(self): 3 for my_job in self.my_jobs: 4 code = city_code.find_code(my_job['city']) 5 wea = getWeath(code) 6 strWea = strDic(wea) 7 title = '{}天氣預報:\n'.format(my_job['city']) 8 sendWeatherMsg(my_job['receivers'], title + strWea)#發送天氣信息給文件助手 9 10 def addMyJobs(self, json_job): 11 self.my_jobs = json_job['items'] 12 scheduler = BackgroundScheduler() 13 scheduler.add_job(self.__sendWeatherMsg, trigger = 'cron', hour = json_job['hour'] 14 , minute = json_job['minute'], second = '5,10,15,20,25,30,35,40,45,50,55') 15 scheduler.start()
後期出現不一樣類型任務時,咱們就須要在封裝新的類。上述MyJob類有2個接口,一個是任務調度器回調接口,不須要咱們調用,另外一個是加載任務接口,這個任務參數是一個標準的json串,由任務觸發時間和具體的任務列表組成,任務觸發時間主要是給調度器使用,任務列表就是調度器觸發時的回調函數須要執行的任務數量。
1 my_jobs = { 2 "id":"my_jobs", 3 "hour":"6, 17", 4 "minute":"30", 5 "items":[{ 6 "receivers":"文件傳輸助手,李靜,拉卡拉", 7 "city":"昌平" 8 },{ 9 "receivers":"文件傳輸助手,李靜,拉卡拉", 10 "city":"海淀" 11 }] 12 }
如上述任務json串來講,咱們的任務id爲my_jobs,在天天的6.30和17.30,咱們須要執行items列表所指出的任務,任務列表是一個列表,列表中存儲的是具體任務,receivers表明任務執行完畢須要發送的好友,city是爬取的天氣名稱,測試效果以下圖所示
因爲任務調度器不是一個阻塞性的程序,若是咱們不在主線程進行阻塞程序,那麼程序就會直接退出,若是阻塞了主線程,那麼任務調度程序也將會被阻塞,所以這裏在添加任務調度後,咱們開啓了一個子線程,主要就是爲了避免讓主線程退出,這樣作其實不合理,可是咱們這裏僅僅是爲了演示,在下篇文章中這些問題咱們在作進一步處理。
1 city_code = city_code.City() 2 city_code.load('city_code.txt') 3 4 if __name__ == "__main__": 5 try: 6 ''' ''' 7 my_job = MyJob() 8 my_job.addMyJobs(test_jobs) 9 10 f = lambda x : lambda y : x+y 11 t = Timer.Timer(f, 24 * 60 * 60)#建立線程 一天給本身發一條消息 12 t.setDaemon(True) 13 t.start() 14 t.join() #防止主主線程退出 15 16 #SendWeatherMsg(my_msg) 17 18 except ResponseError as e: 19 print(e.err_code, e.err_msg) # 查看錯誤號和錯誤消息
喜歡的同窗能夠本身嘗試完成下這個小程序,或者選擇一個相似的場景進行處理,本篇文章中還有幾個須要優化的地方,因爲篇幅問題,咱們在下篇中進行講解
一、定時任務作成windows服務,這樣更優雅,隨開機啓動
二、發送消息給微信好友換成發送郵件給指定郵箱
須要所有代碼的到csdn直接下載:Python-定時爬取指定城市天氣(一)-發送給關心的微信好友
轉載聲明:本站文章無特別說明,皆爲原創,版權全部,轉載請註明:朝十晚八