文中有些代码出现了render是因为该函数是在Django框架下写的
一、国内省份疫情
1、获取百度接口数据
def getData():
"""爬虫获取数据"""
url = "https://voice.baidu.com/newpneumonia/get?target=trend&isCaseIn=0&stage=publish&&qq-pf-to=pcqq.groupnewpneumonia"
# 请求头,作用:伪装成浏览器反爬虫(虽然这个链接就是用来爬的)
headers = {
'user-agent': 'User-Agent: Mozilla/5.0 (Windows NT 10.0 Win64 x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36',
}
# 这个网址请求方式为get
r = requests.get(url, headers)
info = json.loads(r.text)
data = info["data"]
# 遍历省份,将所有省份的名字按序存储到name_list
for i in range(len(data)):
name = data[i]["name"]
name_list.append(name)
return data
其中的data结构就是这样的。
2、对该省份数据进行处理,使之能用于pyecharts
下面的代码除了正常的从json中提取所需日期、省份的数据外,也对某些日期没有上报疫情信息的情况做了try-except异常处理(因为港澳台等地的信息更新不及时)。处理思想如下:
(1)如果是当天信息没有上报才导致的日期列表没有该日期,那就用二分法找前一个有上报信息的日期,代码如下
def BinarySearch(array_strlist, t):
"""
二分法找不存在的日期的前一个日期的索引
:param array_strlist:
:param t:
:return:
"""
mid = 0
array = [int(float(x) * 100) for x in array_strlist]
low = 0
height = len(array) - 1
while low < height:
mid = (low + height) // 2
if array[mid] < t:
low = mid + 1
elif array[mid] > t:
height = mid - 1
# else:
# return array[mid]
return mid - 1
(2)如果是因为不存在日期2.30、2.31,也不告诉用户该日期不合法,直接就用前1天或前2天的数据顶上。下面是处理出具体的每个省份、日期下的疫情数据的代码
def getSpecial(data, date, kind="新增"):
"""
获取具体的每个省份、日期下的疫情数据
:param kind:
:param data: getData函数返回的数据(字典类型)
:param date: 要显示的日期
:return: 返回指定指定日期的数据
"""
province_info = {}
# 获取想要的日期的下标(因为除港澳台等地,各个省的信息的日期都一样,干脆用第一个北京的日期列表找索引)
try:
idx = data[0]["trend"]["updateDate"].index(date)
except:
# 如果当天不存在(这里不是没有上报,而是如2月没有30号、31号的情况),那就用前1天或前2天的数据顶上
# 这里的算法确实没有考虑告诉用户该日期不合法,稍微粗糙一些
try:
date_list = date.split('.')
date_list[1] = str(int(date_list[1]) - 1)
idx = data[0]["trend"]["updateDate"].index(".".join(date_list))
except:
date_list = date.split('.')
date_list[1] = str(int(date_list[1]) - 2)
idx = data[0]["trend"]["updateDate"].index(".".join(date_list))
#
for i in range(len(data)):
if kind == "确诊":
# 想要的日期下 确诊人数
try:
confirm = data[i]["trend"]["list"][0]["data"][idx]
except:
old_date_idx = BinarySearch(data[i]["trend"]["list"][0]["data"], int(float(date) * 100))
confirm = data[i]["trend"]["list"][0]["data"][old_date_idx]
province_info.update({data[i]["name"]: confirm})
if kind == "治愈":
# 想要的日期下 治愈人数
try:
cured = data[i]["trend"]["list"][1]["data"][idx]
except:
old_date_idx = BinarySearch(data[i]["trend"]["list"][1]["data"], int(float(date) * 100))
cured = data[i]["trend"]["list"][1]["data"][old_date_idx]
province_info.update({data[i]["name"]: cured})
if kind == "死亡":
# 想要的日期下 死亡人数
try:
death = data[i]["trend"]["list"][2]["data"][idx]
except:
old_date_idx = BinarySearch(data[i]["trend"]["list"][2]["data"], int(float(date) * 100))
death = data[i]["trend"]["list"][2]["data"][old_date_idx]
province_info.update({data[i]["name"]: death})
if kind == "新增":
# 想要的日期下 新增确诊人数
try:
newConfirm = data[i]["trend"]["list"][3]["data"][idx]
except:
newConfirm = 0
province_info.update({data[i]["name"]: newConfirm})
return province_info
3、写一个初始化pyecharts地图函数
def map_init(date=None, kind="新增"):
"""
初始化map并返回,被display和lunbo引用
:param date: 日期,默认为None
:return:
"""
# maptype='china' 只显示全国直辖市和省级
map_ = Map()
map_.set_global_opts(
title_opts=opts.TitleOpts(title=f"2020{date}中国疫情{kind}地图"),
visualmap_opts=opts.VisualMapOpts(max_=3600, is_piecewise=True,
pieces=[
{"max": 5000, "min": 1001, "label": ">1000", "color": "#8A0808"},
{"max": 1000, "min": 500, "label": "500-1000", "color": "#B40404"},
{"max": 499, "min": 100, "label": "100-499", "color": "#DF0101"},
{"max": 99, "min": 10, "label": "10-99", "color": "#F78181"},
{"max": 9, "min": 1, "label": "1-9", "color": "#F5A9A9"},
{"max": 0, "min": 0, "label": "0", "color": "#FFFFFF"},
], ), # 最大数据范围,分段
)
return map_
4、绘制各省份的 确诊/死亡/治愈/新增 疫情地图
显示函数是:
def display(province_distribution, date, kind="新增"):
"""
全国地图-非轮播图
:param kind:
:param province_distribution: 省和直辖市
:param date:
:return:
"""
map_ = map_init(date=date)
map_.add(f"2020{date}中国疫情{kind}地图", data_pair=list(province_distribution.items()), maptype="china", is_roam=True)
map_.render(f'2020{date}中国疫情地图.html')
调用函数为:
date = "7.29"
kind = "新增"
# 获取全国各省份数据(种类可选有:确诊/死亡/治愈/新增)
province_distribution = getSpecial(data, date, kind)
# 展示全国地图
display(province_distribution, date, kind)
5、绘制各省份的 确诊/死亡/治愈/新增 疫情轮播地图
下面代码中加上了定到当前日期的功能,意味着你何时运行代码,就会不仅重新爬取数据,还会随着时间重新制作到当前时间的轮播图(下面写的是10天为步长,你可以修改)
def lunbo(data, kind="新增"):
"""
全国地图-轮播图
:param data: 同上
:param kind:
:return:
"""
# maptype='china' 只显示全国直辖市和省级
# 制作轮播
timeline = Timeline()
# map_list = []
from datetime import datetime
# 定到当月
for month in range(2, datetime.now().month + 1):
# 如果当月刚开始(还没到10天呢),
for day in range(1, 31 if (month != datetime.now().month) else datetime.now().day, 10):
nowDate = f"{month}.{day}"
map_ = map_init(date=nowDate)
province_distribution = getSpecial(data, nowDate, kind)
map_.add(f"2020{month}月{day}日中国疫情{kind}地图", data_pair=list(province_distribution.items()), maptype="china",
is_roam=True)
timeline.add(map_, f"{month}月{day}日")
# 自动播放,播放延迟1s
timeline.add_schema(is_auto_play=True, play_interval=1000)
timeline.render("轮播.html")
调用函数为:
lunbo(data)