-
Python | 新冠肺炎疫情数据的爬取与可视化分析
前言
这两年,新冠肺炎肆虐而来,随着确诊人数的不断上升,全世界的人都陷入了恐慌中。我们经常能在手机、电视上看到各个地区疫情的情况,但那些数据大多数都是零碎的,我们不可能去记住每个数据,但我们可以用爬虫爬取各个地区发出的新闻数据,再将这些数据进行整理分析。所以我们在疫情期间可以通过访问一个网站,就能知道各个地区的疫情情况。
数据来源
中国的新冠肺炎疫情数据
国外的新冠肺炎疫情数据
爬虫设计方案
1. 爬虫名称
新冠肺炎疫情数据的爬取与可视化分析
2. 爬取内容与数据特征分析
爬取的内容包括了全球新冠肺炎疫情数据、中国各省市新冠肺炎疫情数据和福建各市新冠肺炎疫情数据。
爬取的数据都由中文和数字组成,所有数字数据都是大于等于0,不会出现小于0的情况。
3. 方案概述
分析网站页面结构,找到爬取数据的位置,根据不同的数据制定不同的爬取方法,将爬取的数据保存成csv文件,然后再将csv文件里的数据进行可视化处理。
网站页面的结构特征分析
1. 网站页面结构分析
从下面的网站截图中可以看出,该网站的结构分为三个部分,一部分是左上的疫情总览,一部分是右边各个地区的疫情消息,还有一部分就是左下各个地区具体的疫情数据,而这部分数据就是我们要爬取的数据。
2. 网站html页面结构分析
从下面的网站html截图中可以看出,该网站由div标签进行分割内容,总共分了两大块,左边和右边,我们需要的数据在左边。
进一步分析网站的html,发现数据都在class=data-list的div标签里,在div标签里的列表标签ul,存放着中国每个省的疫情数据。
在li标签下,还有一个div,这个div里的ul列表存放的数据是每个省市的数据。
3. 标签查找方法与遍历方法
通过上面网站html页面的分析,可以画出标签树。
(1)地区名称所在标签的查找方法
各个省份的名称在class=list-pro-name的div标签里,而各省份的城市的名称在class=list-city-name的div标签里。因为这两个标签的class属性不同,所以可以用BeautifulSoup库的find()方法,利用标签属性值检索。
(2)地区疫情数据所在标签的查找方法
从上面的标签树中可以看出,省疫情数据和市疫情数据分别在不同的li标签下的div标签里,第二个li是第一个li的子标签。在这两个标签之间没有可以唯一标识的熟悉,所以要查找到这两个标签需要BeautifulSoup库的CSS选择器,通过标签的父子关系分别找到两个li标签。
爬虫程序设计
1. 数据的爬取
(1)中国新冠疫情数据的爬取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 获取中国每个省的疫情数据
def getProvinceData(html):
total_data=[]
temporary=[]
new_diagnosis_data=[]
cumulative_diagnosis_data=[]
cured_data=[]
dead_data=[]
soup = BeautifulSoup(html,'html.parser')
# 找到 class=data-list 的div标签
data = soup.find('div',{'class':'data-list'})
ul = data.find('ul')
div = ul.find_all('div',{'class':'list-pro-name'})
province_name_data=[]
for i in div:
# 获取省的名称
# 省名称在label标签里
province_name = i.find('label').string
province_name_data.append(province_name)
# 用CSS选择器获取第一层的数据(每个省的数据)
diagnosis = soup.select('div.data-list > ul > li > div.list-city-data')
for i in diagnosis:
temporary.append(i.string)
total = [temporary[i:i+4] for i in range(0,len(temporary),4)]
for i in range(len(total)):
# 获取新增确诊人数
new_diagnosis_data.append(total[i][0])
# 获取累计确诊人数
cumulative_diagnosis_data.append(total[i][1])
# 获取治愈人数
cured_data.append(total[i][2])
# 获取死亡人数
dead_data.append(total[i][3])
total_data.append(province_name_data)
total_data.append(new_diagnosis_data)
total_data.append(cumulative_diagnosis_data)
total_data.append(cured_data)
total_data.append(dead_data)
return total_data
(2)福建省新冠疫情数据的爬取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 获取福建省每个市的疫情数据
def getCitiData(html):
citi_name_data=[]
new_diagnosis_data=[]
cumulative_diagnosis_data=[]
cured_data=[]
dead_data=[]
total_data=[]
soup = BeautifulSoup(html,'html.parser')
data = soup.find('div',{'class':'data-list'})
# 找到有唯一标识的属性的input标签
input1 = data.find('input',{'id':'_209'})
# 找到input标签的的父标签
div = input1.parent
# 找到所有的li
li = div.find_all('li')
# 遍历li组成的列表
for i in range(1,len(li)):
# 获取市名称
citi_name = li[i].find('div',{'class':'list-city-name'})
citi_name_data.append(citi_name.string+'市')
div = li[i].find_all('div',{'class':'list-city-data'})
# 获取新增确诊人数
new_diagnosis = div[0].string
new_diagnosis_data.append(new_diagnosis)
# 获取累计确诊人数
cumulative_diagnosis = div[1].string
cumulative_diagnosis_data.append(cumulative_diagnosis)
# 获取治愈人数
cured = div[2].string
cured_data.append(cured)
# 获取死亡人数
dead = div[3].string
dead_data.append(dead)
total_data.append(citi_name_data)
total_data.append(new_diagnosis_data)
total_data.append(cumulative_diagnosis_data)
total_data.append(cured_data)
total_data.append(dead_data)
return total_data
(3)国外新冠疫情数据的爬取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 获取全球每个国家的疫情数据
def getWorldData(html):
country_name_data=[]
new_diagnosis_data=[]
cumulative_diagnosis_data=[]
cured_data=[]
dead_data=[]
total_data=[]
soup = BeautifulSoup(html,'html.parser')
data = soup.find('div',{'class':'data-list'})
# 因为有两层li,我们需要的是第二层的li,所以可以通过CSS选择器来获取第二层的li
data_list = data.select('ul > li > div > div > ul > li')
for i in range(12,len(data_list)-1):
div = data_list[i].find_all('div')
# 获取国家名称
country_name = div[0].string
country_name_data.append(country_name)
# 获取新增确诊人数
new_diagnosis = div[1].string
new_diagnosis_data.append(new_diagnosis)
# 获取累计确诊人数
cumulative_diagnosis = div[2].string
cumulative_diagnosis_data.append(cumulative_diagnosis)
# 获取治愈人数
cured = div[3].string
cured_data.append(cured)
# 获取死亡人数
dead = div[4].string
dead_data.append(dead)
total_data.append(country_name_data)
total_data.append(new_diagnosis_data)
total_data.append(cumulative_diagnosis_data)
total_data.append(cured_data)
total_data.append(dead_data)
return total_data
(4)保存数据
疫情数据爬取完后,通过Pandask库的to_csv()方法,将爬取后的数据保存为csv文件。
保存后的部分数据:
2. 数据清洗与处理
(1)因为全球疫情的数据量较大,所以我们可以通过pandas库来查看数据是否有异常、缺失、重复
1
2
3
4
5
import pandas as pd
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
# 查看数据的简要信息
df_world.describe()
(2)通过查看数据的简要信息,数据正常,数据的最小值也不是负数
(3)通过pandas库的isnull()方法查看是否有空值
1
2
# 查看是否有空值,有空值返回True,没有空值返回False
df_world.isnull().value_counts()
(4)通过pandas库的duplicated()方法查看是否有重复行
1
2
# 查看是否有重复行,有重复行返回True,没有重复行返回False
df_world.duplicated()
(5)为了之后能更好的分析数据,需要对数据进行排序,后面再排序也可以
1
2
#根据累计确诊人数对数据进行降序排序
df = df_world.sort_values(by='累计确诊',ascending=False)
(6)保存处理后的数据
1
2
3
4
5
6
#保存处理后的数据
import pandas as pd
df = df.set_index('名称')
df.to_csv("各国家的新冠肺炎疫情数据.csv",encoding='utf-8')
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
df_world.head()
3. 数据可视化分析
(1)中国新冠肺炎疫情地图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 用pyecharts库画中国新冠疫情地图
from pyecharts import options as opts
from pyecharts.charts import Map
import pandas as pd
# 自定义分段图例
pieces=[
{"max": 70000, "min": 3000, "label": ">3000", "color": "#B40404"},
{"max": 3000, "min": 1000, "label": "1000-3000", "color": "#DF0101"},
{"max": 1000, "min": 100, "label": "100-1000", "color": "#F78181"},
{"max": 100, "min": 10, "label": "10-100", "color": "#F5A9A9"},
{"max": 10, "min": 0, "label": "<10", "color": "#FFFFCC"},
]
name = []
values = []
# 导入数据
df = pd.DataFrame(pd.read_csv("各省的新冠肺炎疫情数据.csv"))
# 处理数据,将数据处理成Map所要求的数据
for i in range(df.shape[0]): # shape[0]:行数,shape[1]:列数
name.append(df.at[i,'名称'])
values.append(str(df.at[i,'累计确诊']))
total = [[name[i],values[i]] for i in range(len(name))]
# 创建地图(Map)
china_map = (Map())
# 设置中国地图
china_map.add("确诊人数",total ,maptype="china",is_map_symbol_show=False)
china_map.set_global_opts(
# 设置地图标题
title_opts=opts.TitleOpts(title="中国各省、直辖市、自治区、特别行政区新冠肺炎确诊人数"),
# 设置自定义图例
visualmap_opts=opts.VisualMapOpts(max_=70000,is_piecewise=True,pieces=pieces),
legend_opts=opts.LegendOpts(is_show=False)
)
# 直接在notebook显示地图,默认是保存为html文件
china_map.render_notebook()
(2)中国确诊人数前15地区的治愈率与死亡率的折线图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pandas as pd
import matplotlib.pyplot as plt
# 创建画布
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
# 导入数据
df_china = pd.read_csv("各省的新冠肺炎疫情数据.csv")
df_china['治愈率'] = df_china['治愈']/df_china['累计确诊']
df_china['死亡率'] = df_china['死亡']/df_china['累计确诊']
plt.plot(df_china.iloc[0:16,0],df_china.iloc[0:16,5],label="治愈率")
plt.plot(df_china.iloc[0:16,0],df_china.iloc[0:16,6],label="死亡率")
# y轴刻度标签
ax.set_yticks([0.05,0.2,0.4,0.6,0.8,1.0])
ax.set_yticklabels(["5 %","20 %","40 %","60 %","80 %","100 %"],fontsize=12)
# 图例
plt.legend(loc='center right',fontsize=12)
# 标题
plt.title("中国确诊人数前15地区的治愈率与死亡率")
# 网格
plt.grid()
plt.show()
(3)中国确诊人数前15地区的新增确诊人数的折线图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import matplotlib.pyplot as plt
# 创建画布
fig=plt.figure(figsize=(10,8))
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_china = pd.read_csv("各省的新冠肺炎疫情数据.csv")
plt.plot(df_china.iloc[0:15,0],df_china.iloc[0:15,1],label="新增确诊")
# 图例
plt.legend(fontsize=12)
# 标题
plt.title("中国确诊人数前15地区的新增确诊人数")
# y轴标签
plt.ylabel('人数')
# 网格
plt.grid()
plt.show()
(4)福建新冠肺炎疫情地图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#用pyecharts库画福建疫情分布地图
import pandas as pd
from pyecharts.charts import Map,Geo
from pyecharts import options as opts
#自定义分段图例
pieces=[
{"max": 100, "min": 70, "label": ">70", "color": "#B40404"},
{"max": 70, "min": 40, "label": "40-79", "color": "#DF0101"},
{"max": 40, "min": 20, "label": "20-40", "color": "#F78181"},
{"max": 20, "min": 10, "label": "10-20", "color": "#F5A9A9"},
{"max": 10, "min": 0, "label": "<10", "color": "#FFFFCC"},
]
name = []
values = []
#导入数据
df_citi = pd.read_csv("各市的新冠肺炎疫情数据.csv")
# 处理数据,将数据处理成Map所要求的数据
for i in range(df_citi.shape[0]): # shape[0]:行数,shape[1]:列数
name.append(df_citi.at[i,'名称'])
values.append(str(df_citi.at[i,'累计确诊']))
total = [[name[i],values[i]] for i in range(len(name))]
# 创建地图
chinaciti_map = (Map())
# 设置福建省地图
chinaciti_map.add("确诊人数",total ,maptype="福建",is_map_symbol_show=False)
chinaciti_map.set_global_opts(
# 地图标题
title_opts=opts.TitleOpts(title="福建各市新冠肺炎确诊人数"),
# 设置自定义图例
visualmap_opts=opts.VisualMapOpts(max_=100,is_piecewise=True,pieces=pieces),
legend_opts=opts.LegendOpts(is_show=False)
)
# 直接在notebook显示地图,默认是保存为html文件
chinaciti_map.render_notebook()
(5)福建新冠肺炎疫情饼图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt
import pandas as pd
# 创建画布
plt.figure(figsize=(6,4))
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_citi = pd.read_csv("各市的新冠肺炎疫情数据.csv")
labels = df_citi['名称'].values
data = df_citi['累计确诊'].values
plt.pie(data ,labels=labels, autopct='%1.1f%%')
#设置显示图像为圆形
plt.axis('equal')
# 标题
plt.title('福建省各市新冠疫情比例')
plt.show()
(6)全球新冠肺炎疫情地图
因为世界地图的国家名是英文的,而爬取的数据的国家名是中文的,国家名对不上会导致数据显示不到地图上,所以要先建一个映射字典,将英文替换成中文
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#中文国家名映射字典
nameMap = {
'Singapore Rep.':'新加坡','Dominican Rep.':'多米尼加','Palestine':'巴勒斯坦','Bahamas':'巴哈马','Timor-Leste':'东帝汶','Afghanistan':'阿富汗',
'Guinea-Bissau':'几内亚比绍',"Côte d'Ivoire":'科特迪瓦','Siachen Glacier':'锡亚琴冰川',"Br. Indian Ocean Ter.":'英属印度洋领土','Angola':'安哥拉',
'Albania':'阿尔巴尼亚','United Arab Emirates':'阿联酋','Argentina':'阿根廷','Armenia':'亚美尼亚','French Southern and Antarctic Lands':'法属南半球和南极领地',
'Australia':'澳大利亚','Austria':'奥地利','Azerbaijan':'阿塞拜疆','Burundi':'布隆迪','Belgium':'比利时','Benin':'贝宁','Burkina Faso':'布基纳法索',
'Bangladesh':'孟加拉国','Bulgaria':'保加利亚','The Bahamas':'巴哈马','Bosnia and Herz.':'波斯尼亚和黑塞哥维那','Belarus':'白俄罗斯','Belize':'伯利兹',
'Bermuda':'百慕大','Bolivia':'玻利维亚','Brazil':'巴西','Brunei':'文莱','Bhutan':'不丹','Botswana':'博茨瓦纳','Central African Rep.':'中非','Canada':'加拿大',
'Switzerland':'瑞士','Chile':'智利','China':'中国','Ivory Coast':'象牙海岸','Cameroon':'喀麦隆','Dem. Rep. Congo':'刚果(金)','Congo':'刚果(布)',
'Colombia':'哥伦比亚','Costa Rica':'哥斯达黎加', 'Cuba':'古巴','N. Cyprus':'北塞浦路斯','Cyprus':'塞浦路斯','Czech Rep.':'捷克','Germany':'德国',
'Djibouti':'吉布提','Denmark':'丹麦','Algeria':'阿尔及利亚','Ecuador':'厄瓜多尔','Egypt':'埃及','Eritrea':'厄立特里亚','Spain':'西班牙','Estonia':'爱沙尼亚',
'Ethiopia':'埃塞俄比亚','Finland':'芬兰','Fiji':'斐','Falkland Islands':'福克兰群岛','France':'法国','Gabon':'加蓬','United Kingdom':'英国','Georgia':'格鲁吉亚',
'Ghana':'加纳','Guinea':'几内亚','Gambia':'冈比亚','Guinea Bissau':'几内亚比绍','Eq. Guinea':'赤道几内亚','Greece':'希腊','Greenland':'格陵兰岛',
'Guatemala':'危地马拉','French Guiana':'法属圭亚那','Guyana':'圭亚那','Honduras':'洪都拉斯','Croatia':'克罗地亚','Haiti':'海地','Hungary':'匈牙利',
'Indonesia':'印度尼西亚','India':'印度','Ireland':'爱尔兰','Iran':'伊朗','Iraq':'伊拉克','Iceland':'冰岛','Israel':'以色列','Italy':'意大利','Jamaica':'牙买加',
'Jordan':'约旦','Japan':'日本','Kazakhstan':'哈萨克斯坦','Kenya':'肯尼亚','Kyrgyzstan':'吉尔吉斯斯坦','Cambodia':'柬埔寨','Korea':'韩国','Kosovo':'科索沃',
'Kuwait':'科威特','Lao PDR':'老挝','Lebanon':'黎巴嫩','Liberia':'利比里亚','Libya':'利比亚','Sri Lanka':'斯里兰卡','Lesotho':'莱索托','Lithuania':'立陶宛',
'Luxembourg':'卢森堡','Latvia':'拉脱维亚','Morocco':'摩洛哥','Moldova':'摩尔多瓦','Madagascar':'马达加斯加','Mexico':'墨西哥','Macedonia':'马其顿',
'Mali':'马里','Myanmar':'缅甸','Montenegro':'黑山','Mongolia':'蒙古国','Mozambique':'莫桑比克', 'Mauritania':'毛里塔尼亚','Malawi':'马拉维',
'Malaysia':'马来西亚','Namibia':'纳米比亚','New Caledonia':'新喀里多尼亚','Niger':'尼日尔','Nigeria':'尼日利亚','Nicaragua':'尼加拉瓜','Netherlands':'荷兰',
'Norway':'挪威','Nepal':'尼泊尔','New Zealand':'新西兰','Oman':'阿曼','Pakistan':'巴基斯坦','Panama':'巴拿马','Peru':'秘鲁','Philippines':'菲律宾',
'Papua New Guinea':'巴布亚新几内亚','Poland':'波兰','Puerto Rico':'波多黎各','Dem. Rep. Korea':'朝鲜','Portugal':'葡萄牙','Paraguay':'巴拉圭',
'Qatar':'卡塔尔','Romania':'罗马尼亚','Russia':'俄罗斯','Rwanda':'卢旺达','W. Sahara':'西撒哈拉','Saudi Arabia':'沙特阿拉伯','Sudan':'苏丹',
'S. Sudan':'南苏丹','Senegal':'塞内加尔','Solomon Is.':'所罗门群岛','Sierra Leone':'塞拉利昂','El Salvador':'萨尔瓦多','Somaliland':'索马里兰',
'Somalia':'索马里','Serbia':'塞尔维亚','Suriname':'苏里南','Slovakia':'斯洛伐克','Slovenia':'斯洛文尼亚','Sweden':'瑞典','Swaziland':'斯威士兰',
'Syria':'叙利亚','Chad':'乍得','Togo':'多哥','Thailand':'泰国','Tajikistan':'塔吉克斯坦','Turkmenistan':'土库曼斯坦','East Timor':'东帝汶',
'Trinidad and Tobago':'特里尼达和多巴哥','Tunisia':'突尼斯','Turkey':'土耳其','Tanzania':'坦桑尼亚','Uganda':'乌干达','Ukraine':'乌克兰',
'Uruguay':'乌拉圭','United States':'美国','Uzbekistan':'乌兹别克斯坦','Venezuela':'委内瑞拉','Vietnam':'越南','Vanuatu':'瓦努阿图','West Bank':'西岸',
'Yemen':'也门','South Africa':'南非','Zambia':'赞比亚','Zimbabwe':'津巴布韦'
}
映射字典弄好后,就可以作图了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#用pyecharts库画全球疫情分布地图
import pandas as pd
from pyecharts.charts import Map,Geo
from pyecharts import options as opts
#自定义分段图例
pieces=[
{"max": 50000000, "min": 10000000, "label": ">1000万", "color": "#8B1A1A"},
{"max": 10000000, "min": 5000000, "label": "500万-1000万", "color": "#CD2626"},
{"max": 5000000, "min": 1000000, "label": "100万-500万", "color": "#EE2C2C"},
{"max": 1000000, "min": 100000, "label": "10万-100万", "color": "#FF3030"},
{"max": 100000, "min": 10000, "label": "10000-10万", "color": "#FA8072"},
{"max": 10000, "min": 1000, "label": "1000-10000", "color": "#FFF8DC"},
{"max": 1000, "min": 0, "label": "<500", "color": "#FFFFF0"},
]
name = []
values = []
# 导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
df_china = pd.read_csv("各省的新冠肺炎疫情数据.csv")
# 因为爬取的全球数据不包括中国,所以要把中国的数据加进去
china_data = sum(df_china['累计确诊'])
values.append(china_data)
name.append('中国')
# 处理数据,将数据处理成Map所要求的数据
for i in range(df_world.shape[0]): # shape[0]:行数,shape[1]:列数
name.append(df_world.at[i,'名称'])
values.append(str(df_world.at[i,'累计确诊']))
total = [[name[i],values[i]] for i in range(len(name))]
world_map = (Map())
#设置地图为世界地图、设置中文国家名、设置不显示国家首都红点
world_map.add("确诊人数",total ,maptype="world",name_map=nameMap,is_map_symbol_show=False)
#设置不显示国家名
world_map.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
world_map.set_global_opts(
# 标题
title_opts=opts.TitleOpts(title="全球各个国家新冠肺炎确诊人数"),
#设置自定义分段图例
visualmap_opts=opts.VisualMapOpts(max_=50000000,is_piecewise=True,pieces=pieces),
legend_opts=opts.LegendOpts(is_show=False)
)
# 直接在notebook显示地图,默认是保存为html文件
world_map.render_notebook()
(7)全球新冠肺炎疫情确诊人数排名前10的国家的条形图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 全球新冠肺炎疫情确诊人数排名前10的国家
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
#画布大小
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
sns.barplot(x = df_world.iloc[0:11,0].values,y =df_world.iloc[0:11,2].values,palette="rocket")
#y轴刻度标签
ax.set_yticks([5000000,10000000,15000000,20000000,25000000,30000000,35000000])
ax.set_yticklabels(["500万","1000万","1500万","2000万","2500万","3000万","3500万"],fontsize=12)
#标题
plt.title("全球新冠肺炎疫情确诊人数排名前10的国家",fontsize=12)
#y轴标签
plt.ylabel("确 诊 人 数")
plt.show()
(8)全球新冠肺炎疫情确诊人数前5国家的确诊人数、治愈人数的条形图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import matplotlib.pyplot as plt
#画布大小
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
#国家
country = df_world.iloc[0:6,0]
#确诊人数
diagnosis = df_world.iloc[0:6,2]
#治愈人数
cured = df_world.iloc[0:6,3]
x = list(range(len(country)))
#设置间距
total_width, n = 0.5, 2
width = total_width / n
#柱状图1
for i in range(len(x)):
x[i] += width
plt.bar(x, diagnosis, width=width, label='确诊人数', tick_label=country,color='#FF3030' )
#柱状图2
for i in range(len(x)):
x[i] += width
plt.bar(x, cured, width=width, label='治愈人数',color='#32CD32')
#y轴刻度标签
ax.set_yticks([5000000,10000000,15000000,20000000,25000000,30000000,35000000])
ax.set_yticklabels(["500万","1000万","1500万","2000万","2500万","3000万","3500万"],fontsize=12)
#标题
plt.title("全球新冠肺炎疫情确诊人数前5国家的确诊人数、治愈人数")
#y轴标签
plt.ylabel("确 诊 人 数",fontsize=12)
#图例
plt.legend(loc='upper right',fontsize=12)
plt.show()
(9)全球新冠肺炎疫情确诊人数前15国家的治愈率与死亡率的折线图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import matplotlib.pyplot as plt
# 创建画布
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
df_world['治愈率'] = df_world['治愈']/df_world['累计确诊']
df_world['死亡率'] = df_world['死亡']/df_world['累计确诊']
plt.plot(df_world.iloc[0:16,0],df_world.iloc[0:16,5],label="治愈率")
plt.plot(df_world.iloc[0:16,0],df_world.iloc[0:16,6],label="死亡率")
#y轴刻度标签
ax.set_yticks([0.05,0.2,0.4,0.6,0.8,1.0])
ax.set_yticklabels(["5 %","20 %","40 %","60 %","80 %","100 %"],fontsize=12)
plt.legend(loc='center right',fontsize=12)
plt.title("全球新冠肺炎疫情确诊人数前15国家的治愈率与死亡率")
plt.grid()
plt.show()
完整代码
疫情数据爬取的完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
import requests
from bs4 import BeautifulSoup
import pandas as pd
# 主函数
def main():
# 中国新冠疫情数据网址
url = "https://www.haoyunbb.com/news/3/36573.html"
html = getUrlData(url)
total_data1 = getProvinceData(html)
total_data2 = getCitiData(html)
# 全球(国外)新冠疫情数据网址
url = "https://www.haoyunbb.com/news/3/39230.html"
html = getUrlData(url)
total_data3 = getWorldData(html)
saveData(total_data1,total_data2,total_data3)
# 获取网页数据
def getUrlData(url):
try:
# get请求,设置超时时间
r = requests.get(url,headers=headers,timeout=30)
r.raise_for_status
r.encoding=r.apparent_encoding
html = r.text
return html
except:
return '发生异常'
# 获取中国每个省的疫情数据
def getProvinceData(html):
total_data=[]
temporary=[]
new_diagnosis_data=[]
cumulative_diagnosis_data=[]
cured_data=[]
dead_data=[]
soup = BeautifulSoup(html,'html.parser')
# 找到 class=data-list 的div标签
data = soup.find('div',{'class':'data-list'})
ul = data.find('ul')
div = ul.find_all('div',{'class':'list-pro-name'})
province_name_data=[]
for i in div:
# 获取省的名称
# 省名称在label标签里
province_name = i.find('label').string
province_name_data.append(province_name)
# 用CSS选择器获取第一层的数据(每个省的数据)
diagnosis = soup.select('div.data-list > ul > li > div.list-city-data')
for i in diagnosis:
temporary.append(i.string)
total = [temporary[i:i+4] for i in range(0,len(temporary),4)]
for i in range(len(total)):
# 获取新增确诊人数
new_diagnosis_data.append(total[i][0])
# 获取累计确诊人数
cumulative_diagnosis_data.append(total[i][1])
# 获取治愈人数
cured_data.append(total[i][2])
# 获取死亡人数
dead_data.append(total[i][3])
total_data.append(province_name_data)
total_data.append(new_diagnosis_data)
total_data.append(cumulative_diagnosis_data)
total_data.append(cured_data)
total_data.append(dead_data)
return total_data
# 获取福建省每个市的疫情数据
def getCitiData(html):
citi_name_data=[]
new_diagnosis_data=[]
cumulative_diagnosis_data=[]
cured_data=[]
dead_data=[]
total_data=[]
soup = BeautifulSoup(html,'html.parser')
data = soup.find('div',{'class':'data-list'})
# 找到有唯一标识的属性的input标签
input1 = data.find('input',{'id':'_209'})
# 找到input标签的的父标签
div = input1.parent
# 找到所有的li
li = div.find_all('li')
# 遍历li组成的列表
for i in range(1,len(li)):
# 获取市名称
citi_name = li[i].find('div',{'class':'list-city-name'})
citi_name_data.append(citi_name.string+'市')
div = li[i].find_all('div',{'class':'list-city-data'})
# 获取新增确诊人数
new_diagnosis = div[0].string
new_diagnosis_data.append(new_diagnosis)
# 获取累计确诊人数
cumulative_diagnosis = div[1].string
cumulative_diagnosis_data.append(cumulative_diagnosis)
# 获取治愈人数
cured = div[2].string
cured_data.append(cured)
# 获取死亡人数
dead = div[3].string
dead_data.append(dead)
total_data.append(citi_name_data)
total_data.append(new_diagnosis_data)
total_data.append(cumulative_diagnosis_data)
total_data.append(cured_data)
total_data.append(dead_data)
return total_data
# 获取全球每个国家的疫情数据
def getWorldData(html):
country_name_data=[]
new_diagnosis_data=[]
cumulative_diagnosis_data=[]
cured_data=[]
dead_data=[]
total_data=[]
soup = BeautifulSoup(html,'html.parser')
data = soup.find('div',{'class':'data-list'})
# 因为有两层li,我们需要的是第二层的li,所以可以通过CSS选择器来获取第二层的li
data_list = data.select('ul > li > div > div > ul > li')
for i in range(12,len(data_list)-1):
div = data_list[i].find_all('div')
# 获取国家名称
country_name = div[0].string
country_name_data.append(country_name)
# 获取新增确诊人数
new_diagnosis = div[1].string
new_diagnosis_data.append(new_diagnosis)
# 获取累计确诊人数
cumulative_diagnosis = div[2].string
cumulative_diagnosis_data.append(cumulative_diagnosis)
# 获取治愈人数
cured = div[3].string
cured_data.append(cured)
# 获取死亡人数
dead = div[4].string
dead_data.append(dead)
total_data.append(country_name_data)
total_data.append(new_diagnosis_data)
total_data.append(cumulative_diagnosis_data)
total_data.append(cured_data)
total_data.append(dead_data)
return total_data
# 保存数据
def saveData(total_data1,total_data2,total_data3):
df1 = data(total_data1)
df2 = data(total_data2)
df3 = data(total_data3)
# 将爬取的数据保存为csv文件
df1.to_csv("各省的新冠肺炎疫情数据.csv",encoding='utf-8')
df2.to_csv("各市的新冠肺炎疫情数据.csv",encoding='utf-8')
df3.to_csv("各国家的新冠肺炎疫情数据.csv",encoding='utf-8')
def data(total_data):
df = pd.DataFrame({'名称':total_data[0],'新增确诊':total_data[1],'累计确诊':total_data[2],'治愈':total_data[3],'死亡':total_data[4]})
# 将名称列设置为索引列
df = df.set_index('名称')
return df
# 程序入口
if __name__== "__main__":
main()
# 数据清洗与处理
#因为全球疫情的数据量较大,所以我们可以通过pandas库来查看数据是否有异常、缺失、重复
import pandas as pd
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
# 查看数据的简要信息
# 通过查看数据的简要信息,数据正常,数据的最小值也不是负数
df_world.describe()
# 查看是否有空值,有空值返回True,没有空值返回False
df_world.isnull().value_counts()
# 查看是否有重复行,有重复行返回True,没有重复行返回False
df_world.duplicated()
#根据累计确诊人数对数据进行降序排序
df = df_world.sort_values(by='累计确诊',ascending=False)
#保存处理后的数据
import pandas as pd
df = df.set_index('名称')
df.to_csv("各国家的新冠肺炎疫情数据.csv",encoding='utf-8')
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
df_world.head()
# 数据可视化
# 用pyecharts库画中国新冠疫情地图
from pyecharts import options as opts
from pyecharts.charts import Map
import pandas as pd
# 自定义分段图例
pieces=[
{"max": 70000, "min": 3000, "label": ">3000", "color": "#B40404"},
{"max": 3000, "min": 1000, "label": "1000-3000", "color": "#DF0101"},
{"max": 1000, "min": 100, "label": "100-1000", "color": "#F78181"},
{"max": 100, "min": 10, "label": "10-100", "color": "#F5A9A9"},
{"max": 10, "min": 0, "label": "<10", "color": "#FFFFCC"},
]
name = []
values = []
# 导入数据
df = pd.DataFrame(pd.read_csv("各省的新冠肺炎疫情数据.csv"))
# 处理数据,将数据处理成Map所要求的数据
for i in range(df.shape[0]): # shape[0]:行数,shape[1]:列数
name.append(df.at[i,'名称'])
values.append(str(df.at[i,'累计确诊']))
total = [[name[i],values[i]] for i in range(len(name))]
# 创建地图(Map)
china_map = (Map())
# 设置中国地图
china_map.add("确诊人数",total ,maptype="china",is_map_symbol_show=False)
china_map.set_global_opts(
# 设置地图标题
title_opts=opts.TitleOpts(title="中国各省、直辖市、自治区、特别行政区新冠肺炎确诊人数"),
# 设置自定义图例
visualmap_opts=opts.VisualMapOpts(max_=70000,is_piecewise=True,pieces=pieces),
legend_opts=opts.LegendOpts(is_show=False)
)
# 直接在notebook显示地图,默认是保存为html文件
china_map.render_notebook()
中国确诊人数前15地区的治愈率与死亡率折线图
import pandas as pd
import matplotlib.pyplot as plt
# 创建画布
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
# 导入数据
df_china = pd.read_csv("各省的新冠肺炎疫情数据.csv")
df_china['治愈率'] = df_china['治愈']/df_china['累计确诊']
df_china['死亡率'] = df_china['死亡']/df_china['累计确诊']
plt.plot(df_china.iloc[0:16,0],df_china.iloc[0:16,5],label="治愈率")
plt.plot(df_china.iloc[0:16,0],df_china.iloc[0:16,6],label="死亡率")
# y轴刻度标签
ax.set_yticks([0.05,0.2,0.4,0.6,0.8,1.0])
ax.set_yticklabels(["5 %","20 %","40 %","60 %","80 %","100 %"],fontsize=12)
# 图例
plt.legend(loc='center right',fontsize=12)
# 标题
plt.title("中国确诊人数前15地区的治愈率与死亡率")
# 网格
plt.grid()
plt.show()
# 中国确诊人数前15地区的新增确诊人数折线图
import pandas as pd
import matplotlib.pyplot as plt
# 创建画布
fig=plt.figure(figsize=(10,8))
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_china = pd.read_csv("各省的新冠肺炎疫情数据.csv")
plt.plot(df_china.iloc[0:15,0],df_china.iloc[0:15,1],label="新增确诊")
# 图例
plt.legend(fontsize=12)
# 标题
plt.title("中国确诊人数前15地区的新增确诊人数")
# y轴标签
plt.ylabel('人数')
# 网格
plt.grid()
plt.show()
#用pyecharts库画福建疫情分布地图
import pandas as pd
from pyecharts.charts import Map,Geo
from pyecharts import options as opts
#自定义分段图例
pieces=[
{"max": 100, "min": 70, "label": ">70", "color": "#B40404"},
{"max": 70, "min": 40, "label": "40-79", "color": "#DF0101"},
{"max": 40, "min": 20, "label": "20-40", "color": "#F78181"},
{"max": 20, "min": 10, "label": "10-20", "color": "#F5A9A9"},
{"max": 10, "min": 0, "label": "<10", "color": "#FFFFCC"},
]
name = []
values = []
#导入数据
df_citi = pd.read_csv("各市的新冠肺炎疫情数据.csv")
# 处理数据,将数据处理成Map所要求的数据
for i in range(df_citi.shape[0]): # shape[0]:行数,shape[1]:列数
name.append(df_citi.at[i,'名称'])
values.append(str(df_citi.at[i,'累计确诊']))
total = [[name[i],values[i]] for i in range(len(name))]
# 创建地图
chinaciti_map = (Map())
# 设置福建省地图
chinaciti_map.add("确诊人数",total ,maptype="福建",is_map_symbol_show=False)
chinaciti_map.set_global_opts(
# 地图标题
title_opts=opts.TitleOpts(title="福建各市新冠肺炎确诊人数"),
# 设置自定义图例
visualmap_opts=opts.VisualMapOpts(max_=100,is_piecewise=True,pieces=pieces),
legend_opts=opts.LegendOpts(is_show=False)
)
# 直接在notebook显示地图,默认是保存为html文件
chinaciti_map.render_notebook()
#福建省各市新冠疫情比例饼图
import matplotlib.pyplot as plt
import pandas as pd
# 创建画布
plt.figure(figsize=(6,4))
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_citi = pd.read_csv("各市的新冠肺炎疫情数据.csv")
labels = df_citi['名称'].values
data = df_citi['累计确诊'].values
plt.pie(data ,labels=labels, autopct='%1.1f%%')
#设置显示图像为圆形
plt.axis('equal')
# 标题
plt.title('福建省各市新冠疫情比例')
plt.show()
#用pyecharts库画全球疫情分布地图
import pandas as pd
from pyecharts.charts import Map,Geo
from pyecharts import options as opts
#自定义分段图例
pieces=[
{"max": 50000000, "min": 10000000, "label": ">1000万", "color": "#8B1A1A"},
{"max": 10000000, "min": 5000000, "label": "500万-1000万", "color": "#CD2626"},
{"max": 5000000, "min": 1000000, "label": "100万-500万", "color": "#EE2C2C"},
{"max": 1000000, "min": 100000, "label": "10万-100万", "color": "#FF3030"},
{"max": 100000, "min": 10000, "label": "10000-10万", "color": "#FA8072"},
{"max": 10000, "min": 1000, "label": "1000-10000", "color": "#FFF8DC"},
{"max": 1000, "min": 0, "label": "<500", "color": "#FFFFF0"},
]
name = []
values = []
# 导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
df_china = pd.read_csv("各省的新冠肺炎疫情数据.csv")
# 因为爬取的全球数据不包括中国,所以要把中国的数据加进去
china_data = sum(df_china['累计确诊'])
values.append(china_data)
name.append('中国')
# 处理数据,将数据处理成Map所要求的数据
for i in range(df_world.shape[0]): # shape[0]:行数,shape[1]:列数
name.append(df_world.at[i,'名称'])
values.append(str(df_world.at[i,'累计确诊']))
total = [[name[i],values[i]] for i in range(len(name))]
world_map = (Map())
#设置地图为世界地图、设置中文国家名、设置不显示国家首都红点
world_map.add("确诊人数",total ,maptype="world",name_map=nameMap,is_map_symbol_show=False)
#设置不显示国家名
world_map.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
world_map.set_global_opts(
# 标题
title_opts=opts.TitleOpts(title="全球各个国家新冠肺炎地图"),
#设置自定义分段图例
visualmap_opts=opts.VisualMapOpts(max_=50000000,is_piecewise=True,pieces=pieces),
legend_opts=opts.LegendOpts(is_show=False)
)
# 直接在notebook显示地图,默认是保存为html文件
world_map.render_notebook()
# 全球新冠肺炎疫情确诊人数排名前10的国家
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
#画布大小
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
sns.barplot(x = df_world.iloc[0:11,0].values,y =df_world.iloc[0:11,2].values,palette="rocket")
#y轴刻度标签
ax.set_yticks([5000000,10000000,15000000,20000000,25000000,30000000,35000000])
ax.set_yticklabels(["500万","1000万","1500万","2000万","2500万","3000万","3500万"],fontsize=12)
#标题
plt.title("全球新冠肺炎疫情确诊人数排名前10的国家",fontsize=12)
#y轴标签
plt.ylabel("确 诊 人 数")
plt.show()
import matplotlib.pyplot as plt
#画布大小
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
#国家
country = df_world.iloc[0:6,0]
#确诊人数
diagnosis = df_world.iloc[0:6,2]
#治愈人数
cured = df_world.iloc[0:6,3]
x = list(range(len(country)))
#设置间距
total_width, n = 0.5, 2
width = total_width / n
#柱状图1
for i in range(len(x)):
x[i] += width
plt.bar(x, diagnosis, width=width, label='确诊人数', tick_label=country,color='#FF3030' )
#柱状图2
for i in range(len(x)):
x[i] += width
plt.bar(x, cured, width=width, label='治愈人数',color='#32CD32')
#y轴刻度标签
ax.set_yticks([5000000,10000000,15000000,20000000,25000000,30000000,35000000])
ax.set_yticklabels(["500万","1000万","1500万","2000万","2500万","3000万","3500万"],fontsize=12)
#标题
plt.title("全球新冠肺炎疫情确诊人数前5国家的确诊人数、治愈人数")
#y轴标签
plt.ylabel("确 诊 人 数",fontsize=12)
#图例
plt.legend(loc='upper right',fontsize=12)
plt.show()
import pandas as pd
import matplotlib.pyplot as plt
# 创建画布
fig=plt.figure(figsize=(10,8))
ax=fig.add_subplot(1,1,1)
#中文字体
plt.rcParams['font.family'] = ['SimHei']
#导入数据
df_world = pd.read_csv("各国家的新冠肺炎疫情数据.csv")
df_world['治愈率'] = df_world['治愈']/df_world['累计确诊']
df_world['死亡率'] = df_world['死亡']/df_world['累计确诊']
plt.plot(df_world.iloc[0:16,0],df_world.iloc[0:16,5],label="治愈率")
plt.plot(df_world.iloc[0:16,0],df_world.iloc[0:16,6],label="死亡率")
#y轴刻度标签
ax.set_yticks([0.05,0.2,0.4,0.6,0.8,1.0])
ax.set_yticklabels(["5 %","20 %","40 %","60 %","80 %","100 %"],fontsize=12)
plt.legend(loc='center right',fontsize=12)
plt.title("全球新冠肺炎疫情确诊人数前15国家的治愈率与死亡率")
plt.grid()
plt.show()
总结
因为这次的主题爬虫爬的是最基础的网站,所以进行的还是比较顺利的。在数据的可视化上,除了用pyecharts库的Map模块将数据显示到地图上花了一些功夫,其他都还好,达到了我的预期效果。
因为现在很多网站是用JSON存储数据或者用JS动态加载数据的,所以之后会多学习这些方面的知识。
出处:https://www.cnblogs.com/yusama/p/14829396.html