Python-定時爬取指定城市天氣(一)-發送給關心的微信好友


一、背景

    上班的日子總是3點一線,家里,公司和上班的路徑,對於一個特別懶得我來說,經常遇到上班路上下雨了,而我卻沒帶傘,多么痛的領悟。最近對python有一種狂熱的學習熱情,寫了4年多的C++代碼,對於python我不能說簡單,但是他做東西確實太快了,現有的第三方資源真的炒雞多,用的我也是不亦樂乎。除了上班忘記帶傘,每天重復性的工作還有很多,比如上下班打卡、每個禮拜的周報,還有如果有關心的女神,也可以做定時發送心里話,或者定時提醒等各種服務。有時候想如果有一個人能按時提醒我就好了,這種想法也就停留了那么幾分鍾就被自己pass掉了,因為別人也可能忘記啊。。。那么這件事是不是可以交給程序來做呢!畢竟程序可是會老老實實的做重復性的工作,而且他們樂此不疲。

    上述問題的場景大多都是需要程序在指定時間、或者指定場合提醒我們該干什么了,本篇文章就定時天氣提醒服務來做開篇,講述使用Python怎么完成這樣一個任務,既然這樣,那我們就開始構思我們的程序吧

二、構思

    看過背景中的需求描述,要實現這個功能,我們需要解決以下這么幾個問題:

1、爬取天氣信息,那么接下來就產生第二個問題了

2、動態獲取指定城市天氣

3、發送天氣信息給指定微信好友

4、定時觸發爬取動作

5、怎么關聯微信賬號

    下面我們將一步一步解決上述幾個問題,並實現我們的需求

三、爬取天氣

    解決問題1:

    對於使用過爬蟲的同學來說,爬取天氣信息並不難,之前也了解過一些爬取web信息的代碼,簡單的爬蟲無非就是那么幾步

1、確定爬取的url,使用瀏覽器打開

2、F12查看網頁布局信息

3、使用xpath或者bs4進行節點定位

4、拿到頁面信息

5、自己拼接爬取到的信息

6、寫文件、寫數據庫、發送網絡等等

    這里貼下我之前寫的幾個簡單爬蟲:

1、Python-爬取校花網視頻(單線程和多線程版本)

2、Python-爬取妹子圖(單線程和多線程版本)

3、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_senderwechat_sender是基於wxpytornado 實現的一個可以將你的網站,爬蟲,腳本等其他應用中各種消息(日志,報警,運行結果等)發送到微信的工具包,有了他我們的消息就可以順利的發送到我們的餓微信賬戶了。

交互流程

    如上圖所示,首先使用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) # 查看錯誤號和錯誤消息

    喜歡的同學可以自己嘗試完成下這個小程序,或者選擇一個類似的場景進行處理,本篇文章中還有幾個需要優化的地方,由於篇幅問題,我們在下篇中進行講解

1、定時任務做成windows服務,這樣更優雅,隨開機啟動

2、發送消息給微信好友換成發送郵件給指定郵箱

七、資源下載 

    需要全部代碼的到csdn直接下載:Python-定時爬取指定城市天氣(一)-發送給關心的微信好友

 

如果您覺得文章不錯,不妨給個 打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!!

 


 

  


很重要--轉載聲明

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM