Python實戰(zhàn)之異步獲取中國天氣信息
前言
本來是想要更新scrapy的,但是怎么說呢,這玩意不難,看著官方文檔,基本上就能做,主要是前面的如果你的爬蟲基礎(chǔ)不好的話,這個scrapy你也玩不好,而且對于大部分的人來說安裝scrapy可能都是個問題,因為有一些歷史遺留的問題,畢竟是從python2過來的老框架。當然還有個原因,我要做的東西,用不上scrapy,能夠用上scrapy如果只是做爬蟲,那必然是分布式爬蟲,但是我這里要做的可能只是一個客戶端,也就是一個spider采集軟件,所以這個scrapy沒法上。
目標
今天我們要搞的是獲取天氣,用的API是中國天氣網(wǎng)。
BaseUrl = "http://wthrcdn.etouch.cn/weather_mini?city={}"
網(wǎng)上呢也有很多,那個直接爬取中國天氣網(wǎng)的爬蟲,但是我就是搞不懂,為啥非要去網(wǎng)頁里面然后去xpath或者正則去搞,明明用的都是同一個api出來的數(shù)據(jù),我為啥要去頁面把人家渲染后的結(jié)果去反向解析出數(shù)據(jù)?我直接拿數(shù)據(jù)不好嘛?
請求格式
回到這里,咱們的這個接口呢,是一個get請求,然后的話,那啥只需要把城市或者編號放在city那個字段就行了,返回結(jié)果是個json,我們把這玩意變成字典后是這樣的
{'data': {'yesterday': {'date': '5日星期六', 'high': '高溫 16℃', 'fx': '東北風(fēng)', 'low': '低溫 9℃', 'fl': '<![CDATA[3級]]>', 'type': '多云'}, 'city': '九江', 'forecast': [{'date': '6日星期天', 'high': '高溫 12℃', 'fengli': '<![CDATA[3級]]>', 'low': '低溫 7℃', 'fengxiang': '東北風(fēng)', 'type': '中雨'}, {'date': '7日星期一', 'high': '高溫 14℃', 'fengli': '<![CDATA[2級]]>', 'low': '低溫 7℃', 'fengxiang': '北風(fēng)', 'type': '多云'}, {'date': '8日星期二', 'high': '高溫 19℃', 'fengli': '<![CDATA[2級]]>', 'low': '低溫 8℃', 'fengxiang': '東南風(fēng)', 'type': '晴'}, {'date': '9日星期三', 'high': '高溫 21℃', 'fengli': '<![CDATA[2級]]>', 'low': '低溫 11℃', 'fengxiang': '東南風(fēng)', 'type': '晴'}, {'date': '10日星期四', 'high': '高溫 23℃', 'fengli': '<![CDATA[1級]]>', 'low': '低溫 11℃', 'fengxiang': '南風(fēng)', 'type': '多云'} ], 'ganmao': '感冒多發(fā)期,適當減少外出頻率,適量補充水分,適當增減衣物。', 'wendu': '8'}, 'status': 1000, 'desc': 'OK'}
請求限制
這里不得不說一下,中國天氣網(wǎng) yyds 這個接口完全沒有限制。為啥,我要做的是獲取全國的天氣信息,包括縣城,中國大大小小幾千個縣城,而且還要分時段去分析,所以每天的請求訪問至少2w起步。如果有限制的話,咱們就得那啥反反爬了,但是通過我的測試,沒問題。
requests非異步獲取
來,我們來先做一個對比,沒有對比就沒有傷害是吧,由于非常簡單我就直接上代碼了。
import requests from datetime import datetime class GetWeather(object): urlWheather = "http://wthrcdn.etouch.cn/weather_mini?city={}" requests = requests error = {} today = datetime.today().day weekday = datetime.today().weekday() week = {0:"星期一",1:"星期二",2:"星期三",3:"星期四",4:"星期五",5:"星期六",6:"星期天"} def __getday(self)->str: day = str(self.today)+"日"+self.week.get(self.weekday) return day def get_today_wheather(self,city:str)->dict: data = self.getweather(city) data = data.get("data").get("forecast") today = self.__getday() for today_w in data: if(today_w.get("date")==today): return today_w def getweather(self,city:str,timeout:int=3)->dict: url = self.urlWheather.format(city) try: resp = self.requests.get(url,timeout=timeout) jsondata = resp.json() return jsondata except Exception as e: self.error['error'] = "天氣獲取異常" return self.error def getweathers(self,citys:list,timeout:int=3): wheathers_data = {} for city in citys: url = self.urlWheather.format(city) try: resp = self.requests.get(url=url,timeout=timeout) wheather_data = resp.json() wheathers_data[city]=wheather_data except Exception as e: self.error['error'] = "天氣獲取異常" return self.error return wheathers_data if __name__ == '__main__': getwheather = GetWeather() start = time.time() times = 1 for i in range(5000): data = getwheather.get_today_wheather("九江") if((times%100==0)): print(data,"第",times,"次訪問") times+=1 print("訪問",times,"次耗時",time.time()-start,"秒")
這段代碼呢,我做了一個簡單的封裝。 我們來看看結(jié)果,5000次訪問花了多久
這里我5000次重復(fù)訪問的是同一個城市 九江
異步獲取
這個代碼的話我是沒有封裝的,所以看起來比較亂。 這里有幾個注意點先說一下
系統(tǒng)上限
由于這個,異步的話還是使用的操作系統(tǒng)的一個底層嘛,所以這個并發(fā)是有上限的,因為這個協(xié)程異步是要不斷切換的是吧??雌饋碛悬c像python自己的多線程,只是這個“多線程”完全是當IO的時候才會切換,不然不會切換。 所以喲啊限制一下
編碼
import time import aiohttp from datetime import datetime import asyncio BaseUrl = "http://wthrcdn.etouch.cn/weather_mini?city={}" WeekIndex = {0:"星期一",1:"星期二",2:"星期三",3:"星期四",4:"星期五",5:"星期六",6:"星期天"} today = datetime.today().day day = str(today)+"日"+WeekIndex.get(datetime.today().weekday()) TIMES = 0 async def request(city:str,semaphore:asyncio.Semaphore,timeout:int = 3): url = BaseUrl.format(city) try: async with semaphore: async with aiohttp.request("GET", url) as resp: data = await resp.json(content_type='') return data except Exception as e: raise e def getwheater(task): data = task.result() return data def get_today_weather(task): global TIMES data = task.result() #得到返回結(jié)果 data = data.get("data").get("forecast") for today_w in data: if (today_w.get("date") == day): TIMES+=1#只有IO操作的時候才會切換,所以這個++操作還是一個原子性操作 if(TIMES%100==0): print(today_w,"第",TIMES,"次訪問") return today_w if __name__ == '__main__': semaphore = asyncio.Semaphore(500) #操作系統(tǒng)上限是同一個時刻509/1024個并發(fā),windows509 linux 1024 start = time.time() tasks = [] for i in range(5000): c = request("九江",semaphore,3) task = asyncio.ensure_future(c) task.add_done_callback(get_today_weather) tasks.append(task) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) print("耗時",time.time() - start,"秒")
到此這篇關(guān)于Python實戰(zhàn)之異步獲取中國天氣信息的文章就介紹到這了,更多相關(guān)Python獲取天氣信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解鎖Python中神器vars內(nèi)置函數(shù)的使用
vars()函數(shù)是一個內(nèi)置函數(shù),用于返回對象的__字典__,其中包含對象的__屬性__,本文主要為大家詳細介紹了vars()函數(shù)的具體使用,需要的小伙伴可以了解下2023-11-11pytorch 中pad函數(shù)toch.nn.functional.pad()的用法
今天小編就為大家分享一篇pytorch 中pad函數(shù)toch.nn.functional.pad()的用法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01ITK 實現(xiàn)多張圖像轉(zhuǎn)成單個nii.gz或mha文件案例
這篇文章主要介紹了ITK 實現(xiàn)多張圖像轉(zhuǎn)成單個nii.gz或mha文件案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07