[练习] 获取新冠肺炎疫情数据
一、前言
前一段时间通过手动摘录国家卫健委数据,及clone GitHub数据仓库的数据,简单做了一个Tableau的数据可视化(链接)。但是由于有手动操作的部分,稍显不便,所以便在网上搜索找到了使用Python获取web数据的方法,自己上手操作练习一下。
二、获取web数据
打开网址:https://news.qq.com/zt2020/page/feiyan.htm ,可以看到如下的界面:
访问界面按下F12,然后刷新网页,在Network
页搜索网页上的一个数字,比如57444,找到两项,可以在Headers
下看到各自的Request URL
(见下图),分别在浏览器的地址栏打开查看其中的内容。
可以看到jmap.212.3.js
和疫情数据关联不大,猜测可能多为地理坐标等信息,而getOnsInfo
里面应该就是我们要找的疫情数据了,下面通过Python的request
库获取数据。
>>> import requests
>>> import json
>>> url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5'
>>> headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}
>>> resp = requests.get(url, headers=headers)
>>> resp_json = resp.json()
>>> data = json.loads(resp_json['data'])
三、探索数据内容
获取数据后,探索一下数据的结构。
>>> type(data)
<class 'dict'>
>>> data.keys()
dict_keys(['lastUpdateTime', 'chinaTotal', 'chinaAdd', 'isShowAdd', 'chinaDayList', 'chinaDayAddList', 'dailyNewAddHistory', 'dailyDeadRateHistory', 'dailyHealRateHistory', 'areaTree', 'articleList'])
可以发现,数据中包含lastUpdateTime
, chinaTotal
, chinaAdd
, isShowAdd
, chinaDayList
, chinaDayAddList
, dailyNewAddHistory
, dailyDeadRateHistory
, dailyHealRateHistory
, areaTree
, articleList
这些内容。
下面以chinaTotal
为例,可以发现在chinaTotal
中有confirm
, suspect
, dead
, heal
, nowConfirm
, nowSevere
这些字段,其他类似,不再重复。
>>> data['chinaTotal']
{'confirm': 68586, 'suspect': 8228, 'dead': 1666, 'heal': 9476, 'nowConfirm': 57444, 'nowSevere': 11272}
根据探索的字段名称,以及将字段值与卫健委数据核对,确认字段所表示的含义,整理如下,其中标红的部分是之前存在,但在最近几次运行时发现已经被移除的内容。
数据梳理结果四、整理数据
在探索了数据的结构后,对整理的方式便有了大概的框架。比如,表名标为黄底的为即时数据,分别成表;表名标为绿底的为每日数据,拼接在一起成为一个大表;areaTree
是世界各国及国内各省市的即时数据,国家、省份、地区各自成表;新闻单独成一表。字段整理方式不再赘述。
整理数据及输出数据的代码请见:https://gitee.com/studentjz/data_analysis_practice/blob/master/nCoV/Python/retrieve_data.py
五、定时取数
为避免每次手动运行取数,写了一个循环,用于定时取数,代码及运行过程如下:
import sys
args = sys.argv
if len(args) != 5:
str_msg = '''\nPlease append parameters after file name.
Parameters:
- script: which script to loop, `raw` or `format`, `format` is deprecated.
- datetime: the datetime which to end the loop, and in format `yyyymmddhhmm`.
- hold(sec): the seconds to hold after one loop.
- leave: 0 or 1,
if 0 then prompt a message box when encounter errors and do nothing after the loop ends,
if 1 then hibernate your PC after the loop ends.
Run like:\n$ python loop_crawler.py raw 202001012200 3600 1'''
print(str_msg)
exit()
else:
[script, p_datetime] = args[1:3]
[hold, leave] = [int(x) for x in args[3:]]
import os
from datetime import datetime
import time
if script == 'raw':
import get_raw_data as udm
elif script == 'format':
print('`retrieve_data.py` is deprecated!')
exit()
# import retrieve_data as udm
t_end = datetime.strptime(p_datetime, '%Y%m%d%H%M')
i = 1
while datetime.now() < t_end:
print('{sep} Loop {num} {sep}'.format(sep='-'*10, num=i))
print('Run time: {}\n'.format(datetime.now()))
try:
udm.main()
except:
str_msg = '{} -- {}\n'.format(datetime.now(), sys.exc_info()[1])
with open('Exceptions.txt', 'a') as f:
f.write(str_msg)
print('-- encounter error --')
if leave == 0:
os.system('msg %username% "Error"')
break
else:
print('{sep} Loop {num} is end {sep}'.format(sep='-'*6, num=i))
print('-'*30 + '\n\n')
if (t_end - datetime.now()).seconds < hold:
break
time.sleep(hold)
i += 1
if leave == 1:
os.system('shutdown /h')
运行过程如下图:
运行过程
六、更新
2020-02-16
运行调试期间多次发现web数据的结构发生了变化,这里没有想到比较简洁的办法来动态调整,如果大家有什么好办法还请指导。如果还有其他不足、不正确的地方,也恳请大家的赐教,谢谢。
2020-02-24
运行期间发现web数据经常发现结构性的变动(具体变动内容请见代码中的注释),由于能力、精力有限,格式化的数据更新到2020-02-23为止,此后仅采集原始数据,不做任何整理,采集脚本请见:https://gitee.com/studentjz/data_analysis_practice/blob/master/nCoV/Python/get_raw_data.py
项目地址:https://gitee.com/studentjz/data_analysis_practice/tree/master/nCoV/Python
七、参考资料
https://blog.csdn.net/zengbowengood/article/details/104171607