任務背景:
調用API接口數據,抽取我們所需類型的數據,并寫入指定mysql數據庫。
先從宏觀上看這個任務,并對任務進行分解:
step1:需要學習python下的通過url讀取數據的方式;
step2:數據解析,也是核心部分,數據格式從python角度去理解,是字典?列表?還是各種嵌套?
step3:連接mysql數據庫,將數據寫入。
從功能上看,該數據獲取程序可以分為3個方法,即step1對應方法request_data(),step2對應方法parse_data(),step3對應data_to_db()。
第一輪,暫不考慮異常,只考慮正常狀態下的功能實現。
1、先看request_data():
1
2
3
4
5
|
import requests def request_data(url): req = requests.get(url, timeout = 30 ) # 請求連接 req_jason = req.json() # 獲取數據 return req_jason |
入參:url地址;return:獲取到的數據。
2、然后看parse_data():
不同的API接口下的數據格式各不相同,需要先理清,打開之后密密麻麻一大串,有的可能連完整的一輪數據間隔在哪都不知道,這時候可以巧用符號{ [ , ] }輔助判斷。
梳理之后,發現本接口下的數據格式為,最外層為字典,我們所需的數據在第一個key“data”下,data對應的value為列表,列表中的每個元素為字典,字典中的部分鍵值
即為我們需要的內容。這樣,就明確了我們的數據結構為字典套列表,列表再套字典的格式,最后一層的字典還存在一鍵多值(比如“weather”)的情況。
當然,還有懶人方法,就是百度json在線解析格式化。
摘取部分數據如下:{"data":[{"timestamp_utc":"2020-08-31T08:00:00","weather":{"icon":"c02d","code":802,
wind_dir":336,"clouds_hi":0,"precip":0.0625},{"timestamp_utc":"2020-08-31T08:00:00","weather":{"icon":"c02d","code":802,},
wind_dir":336,"clouds_hi":0,"precip":0.0625],"city_name":"Dianbu","lon":117.58,"timezone":"Asia\/Shanghai","lat":31.95,"country_code":"CN"}
1
2
3
4
5
6
7
8
9
|
def parse_data(req_jason): data_trunk = req_jason[ 'data' ] # 獲取data鍵值下的列表 time_now = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) #獲取當前時刻 for i in range ( len (data_trunk)): data_unit = data_trunk[i] # 依次獲取列表下第i個元素即字典 del data_unit[ 'weather' ] # 刪除該字典中不需要的一鍵多值的key和value,不刪除的話會影響后續的dataframe轉換,但是,如果該鍵值需要的話,需要采取其他處理方式 df = pd.DataFrame([data_unit]) # 將刪除鍵值后的字典轉為datafrme list_need = [ 'timestamp_utc' , 'wind_dir' , 'precip' , 'clouds_hi' ] # 列出我們需要的列 df_need = df[list_need] # 保留df中需要的列 10 df_need.insert(0, 'update_time', time_now) #表格中還需額外增加獲取數據的當前時間,并且需要放在dataframe的第一列 |
備注:數據插入數據庫,有兩種方式,一種是采用insert的sql語句,采用字典的形式插入,另一種是采用dataframe的方式,采用pandas中的to_sql方法。本案例選擇了后者,所以在數據解析時,將字典數據轉成dataframe格式。
入參:獲取到的數據;return值:無
運行以后,發現這樣的程序存在一些問題:就是這個for循環括起來的過多,導致寫數據庫時是一條條寫入而不是一整塊寫入,會影響程序效率,所以需要對程序進行如下修改:
1
2
3
4
5
6
7
8
9
10
|
def parse_data(req_jason): data_trunk = req_jason[ 'data' ] # 獲取data鍵值下的列表 time_now = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) #獲取當前時刻 for i in range ( len (data_trunk)): data_unit = data_trunk[i] # 依次獲取列表下第i個元素即字典 del data_unit[ 'weather' ] # 刪除該字典中不需要的一鍵多值的key和value,不刪除的話會影響后續的dataframe轉換,但是,如果該鍵值需要的話,需要采取其他處理方式 df = pd.DataFrame(data_trunk) # 將刪除鍵值后的整個列表套字典轉為datafrme list_need = [ 'timestamp_utc' , 'wind_dir' , 'precip' , 'clouds_hi' ] # 列出我們需要的列 df_need = df[list_need] # 保留df中需要的列 df_need.insert( 0 , 'update_time' , time_now) #表格中還需額外增加獲取數據的當前時間,并且需要放在dataframe的第一列 |
也就是從第7行之后跳出循環;
如果覺得for循環影響整體美觀,也可以用map代替,將代碼第4/5/6行改為如下代碼,不過性能上來說可能還是for循環更好,具體對比可看其他博主的測試,或者自己測試下運行時間。
1
|
map (data_trunk.pop, [ 'weather' ]) |
3. 最后就是data_to_sql():
1
2
3
4
5
|
def data_to_sql(df): table = 'request_data_api' engine = create_engine( "mysql+pymysql://" + 'root' + ":" + '123' + "@" + 'localhost' + ":" + '3306' + "/" + 'test' + "?charset=utf8" ) df.to_sql(name = table, con = engine, if_exists = 'append' , index = False , index_label = False ) |
入參:dataframe類型數據。
當當當,正常部分已完成,就下來就需要想象各種異常以及處理對策。
第二輪,想象各種異常以及異常的記錄與處理對策。
1.讀取url后,獲取不到數據 → 休息幾秒,嘗試再次重連獲取
2.連接數據庫異常 → 數據庫可能關閉,嘗試重新ping,
3.寫入數據庫的內容為空 → 記錄異常,放棄入庫
第三輪,讓程序定時跑起來。
方法一:在代碼中采用apscheduler下的cron功能(trigger='cron‘,類似linux下的crontab)實現定時運行(當然,apscheduler還有另一種trigger=‘interval'模式);
方法二:在linux下的crontab增加定時任務。
具體可以看別的帖子。
以上就是python 調用API接口 獲取和解析 Json數據的詳細內容,更多關于python 解析數據的資料請關注服務器之家其它相關文章!
原文鏈接:https://www.cnblogs.com/xiamibao/p/13589798.html