新型冠状病毒数据抓取及整理详细流程

前言

  • 数据源:腾讯新闻肺炎疫情
  • 数据爬取工具:requests-html (python 3.5及以上版本)
  • 360极速浏览器 (其他浏览器可以类似找到‘开发者工具’)

需要注意的是,数据源之所以选择腾讯新闻,是因为腾讯新闻最容易抓取。你可以直接通过分析URL得到数据网址,并将这些数据存储为json文件。但是同样的过程,你并不能在其他门户新闻网站上进行。因此,腾讯新闻是最容易抓取疫情数据的网站。(或许有爬虫大佬能告诉我怎么在其他网站,比如百度新闻网站上爬取疫情数据,抱拳,感激不尽~)

步骤一:分析URL

首先,打开开发者工具,可以看到这样的画面:
在这里插入图片描述
其次,找到指向数据的URL。有两种方式:
1、如下图,我们分别标记 a a , b b , c c d d a a : 点击‘Network’(不同浏览器可能名字不同); b b :在Search搜索框内输入在页面上看到的数据,比如,全国确诊数’34664’; c c :搜索框下方会出现URL;双击,点击 d d
在这里插入图片描述
经过上面的操作,可以看到下面图片的内容:
在这里插入图片描述
抄录其中的’Request URL’,为
URL=https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=jQuery34104299452223702189_1581164803507&_=1581164803508
参考大佬们(大佬A大佬B)的博客,知道

  • name=disease_h5 是数据位置
  • callback=jQuery34104299452223702189_1581164803507&_=1581164803508返回当前时间戳的一个函数

我们只需要知道数据位置就行,因此,我们得到
URL=https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5

步骤二:数据采集

数据采集部分将主要参考@Hakuna_Matata_001的内容。

第一步:导入第三方库

import time
import json
import pandas as pd
import numpy as np
from datetime import datetime
# 这里requests-html需要python3.5以上版本
from requests-html import HTMLSession

第二步:抓取数据

# 创建会话
session = HTMLSession();
url = r'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5';
# 从目标网址中读取数据
r = session.get(rul).json();
# 将数据存储为json格式
data = json.loads(r['data']);

看看data里面都是什么

print(data.keys());

输出结果为

dict_keys(['chinaTotal', 'chinaAdd', 'lastUpdateTime', 'areaTree', 'chinaDayList', 'chinaDayAddList', 'isShowAdd', 'articleList'])

从输出结果可以看出来,data是一个字典,其中键有[‘国内总量’, ‘国内新增’, ‘更新时间’, ‘地区数据’, ‘每日数据’, ‘每日增加数据’, ‘是否显示增加’, ‘文章列表’]。

第三步:数据处理

我们最终想要什么样的数据?

  • 国内疫情关于时间的变化序列
  • 当天中国地区和世界其他地区的疫情情况

第一类数据储存在‘每日数据’和‘每日增加数据’中,第二类数据储存在‘地区数据’中。

在正式处理数据之前,我们不妨来看看 ‘国内总量’, ‘国内新增’, ‘更新时间’, ‘是否显示增加’和‘文章列表’这些数据分别是什么样子:

# 国内总量
print(data['chinaTotal']);
# 国内新增
print(data['chinaAdd']);
# 更新时间
print(data['lastUpdateTime']);
# 文章列表
print(data['articleList']);

打印出来,是这样的

# 国内总量
{'confirm': 37251, 'suspect': 28942, 'dead': 812, 'heal': 2651};
# 国内新增
{'confirm': 2653, 'suspect': 1285, 'dead': 89, 'heal': 599};
# 更新时间
2020-02-09 10:25:01;
# 文章列表太长,各位大佬可以自行打印~

下面,我们将国内疫情关于时间的变化序列存储成dataframe。

# 每日数据(将'date'列排在第一列)
chinaDayData = pd.DataFrame(data['chinaDayList'])[['date', 'confirm', 'suspect', 'dead', 'heal', 'deadRate', 'healRate']];
print(chinaDayData);
# 每日新增数据(将'date'列排在第一列)
chinaDayAddData = pd.DataFrame(data['chinaDayAddList'])[['date', 'confirm', 'suspect', 'dead', 'heal', 'deadRate', 'healRate']];
print(chinaDayAddData);

输出结果为

# 每日数据
     date  confirm  suspect  dead  heal deadRate healRate
0   01.13       41        0     1     0      2.4      0.0
1   01.14       41        0     1     0      2.4      0.0
2   01.15       41        0     2     5      4.9     12.2
3   01.16       45        0     2     8      4.4     17.8
4   01.17       62        0     2    12      3.2     19.4
5   01.18      198        0     3    17      1.5      8.6
6   01.19      275        0     4    18      1.5      6.5
7   01.20      291       54     6    25      2.1      8.6
8   01.21      440       37     9    25      2.0      5.7
9   01.22      571      393    17    25      3.0      4.4
10  01.23      830     1072    25    34      3.0      4.1
11  01.24     1287     1965    41    38      3.2      3.0
12  01.25     1975     2684    56    49      2.8      2.5
13  01.26     2744     5794    80    51      2.9      1.9
14  01.27     4515     6973   106    60      2.3      1.3
15  01.28     5974     9239   132   103      2.2      1.7
16  01.29     7711    12167   170   124      2.2      1.6
17  01.30     9692    15238   213   171      2.2      1.8
18  01.31    11791    17988   259   243      2.2      2.1
19  02.01    14380    19544   304   328      2.1      2.3
20  02.02    17236    21558   361   475      2.1      2.8
21  02.03    20471    23214   425   632      2.1      3.1
22  02.04    24363    23260   491   892      2.0      3.7
23  02.05    28060    24702   564  1153      2.0      4.1
24  02.06    31211    26359   637  1542      2.0      4.9
25  02.07    34598    27657   723  2052      2.1      5.9
26  02.08    37251    28942   812  2651      2.2      7.1

# 每日新增数据
     date  confirm  suspect  dead  heal deadRate healRate
0   01.20       77       27     0     0      0.0      0.0
1   01.21      149       53     3     0      2.0      0.0
2   01.22      131      257     8     0      6.1      0.0
3   01.23      259      680     8     6      3.1      2.3
4   01.24      444     1118    16     3      3.6      0.7
5   01.25      688     1309    15    11      2.2      1.6
6   01.26      769     3806    24     2      3.1      0.3
7   01.27     1771     2077    26     9      1.5      0.5
8   01.28     1459     3248    26    43      1.8      2.9
9   01.29     1737     4148    38    21      2.2      1.2
10  01.30     1982     4812    43    47      2.2      2.4
11  01.31     2102     5019    46    72      2.2      3.4
12  02.01     2590     4562    45    85      1.7      3.3
13  02.02     2829     5173    57   147      2.0      5.2
14  02.03     3235     5072    64   157      2.0      4.9
15  02.04     3893     3971    65   262      1.7      6.7
16  02.05     3697     5328    73   261      2.0      7.1
17  02.06     3143     4833    73   387      2.3     12.3
18  02.07     3401     4214    86   510      2.5     15.0
19  02.08     2657     3916    89   600      3.3     22.6

通过观察,我们发现 每日新增数据 可以通过 每日数据 得到,而且 每日新增数据 记录日期还较少,因此,我们仅用 每日数据

我们还需要看看每一列的数据类型,如下:

print(chinaDayData.info());
Data columns (total 7 columns):
date        20 non-null object
confirm     20 non-null int64
suspect     20 non-null int64
dead        20 non-null int64
heal        20 non-null int64
deadRate    20 non-null object
healRate    20 non-null object
dtypes: int64(4), object(3)
memory usage: 1.2+ KB
None

可以看到,不但’data’是object类型,'deadRate’和’healRate’同样也是object类型。为了后面处理方便,我们需要将’deadRate’和’healRate’的数据类型改成float,操作如下:

# 将'deadRate'列的数据类型改成float
chinaDayData.deadRate = chinaDayData.deadRate.map(float);
# 将'healRate'列的数据类型改成float
chinaDayData.healRate = chinaDayData.healRate.map(float);

接下来,我们根据 每日数据 的第一列生成 每日增加数据 列,默认第一天增加数为0。鉴于当天确认数都是凌晨以后,所以当天增加计算公式为 当天增加数=当天确认数-昨天确认数

# 计算第二天直到最后一天的每天增加数
add = [chinaDayData['confirm'][i]-chinaDayData['confirm'][i-1] for i in range(1, len(chinaDayData['confirm']))];
# 默认第一天增加数为0
add.insert(0, 0);
# 创建新的列add
chinaDayData['add'] = add;
# 打印数据
print(chinaDayData);
     date  confirm  suspect  dead  heal deadRate healRate   add
0   01.13       41        0     1     0      2.4      0.0     0
1   01.14       41        0     1     0      2.4      0.0     0
2   01.15       41        0     2     5      4.9     12.2     0
3   01.16       45        0     2     8      4.4     17.8     4
4   01.17       62        0     2    12      3.2     19.4    17
5   01.18      198        0     3    17      1.5      8.6   136
6   01.19      275        0     4    18      1.5      6.5    77
7   01.20      291       54     6    25      2.1      8.6    16
8   01.21      440       37     9    25      2.0      5.7   149
9   01.22      571      393    17    25      3.0      4.4   131
10  01.23      830     1072    25    34      3.0      4.1   259
11  01.24     1287     1965    41    38      3.2      3.0   457
12  01.25     1975     2684    56    49      2.8      2.5   688
13  01.26     2744     5794    80    51      2.9      1.9   769
14  01.27     4515     6973   106    60      2.3      1.3  1771
15  01.28     5974     9239   132   103      2.2      1.7  1459
16  01.29     7711    12167   170   124      2.2      1.6  1737
17  01.30     9692    15238   213   171      2.2      1.8  1981
18  01.31    11791    17988   259   243      2.2      2.1  2099
19  02.01    14380    19544   304   328      2.1      2.3  2589
20  02.02    17236    21558   361   475      2.1      2.8  2856
21  02.03    20471    23214   425   632      2.1      3.1  3235
22  02.04    24363    23260   491   892      2.0      3.7  3892
23  02.05    28060    24702   564  1153      2.0      4.1  3697
24  02.06    31211    26359   637  1542      2.0      4.9  3151
25  02.07    34598    27657   723  2052      2.1      5.9  3387
26  02.08    37251    28942   812  2651      2.2      7.1  2653

我们接着处理 地区数据(areaData=data[‘areaTree’])。 地区数据是一个字典list,一个国家用一个字典储存。

# 地区数据
areaData=data['areaTree']
print('总共有%d个国家,包括' % len(areaData));
for country in areaData:
	print(country['name']);
总共有25个国家,包括
中国
日本
新加坡
泰国
韩国
马来西亚
澳大利亚
越南
德国
美国
法国
阿联酋
加拿大
英国
印度
意大利
菲律宾
俄罗斯
芬兰
斯里兰卡
西班牙
瑞典
柬埔寨
尼泊尔
比利时

中国地区作为一个整体,里面包含整个中国的整体数据,以及每个省份及城市的具体数据。我们将直接提取各个省份及城市的信息。

# 地区数据,是一个列表
areaData=data['areaTree'];
# 中国数据,是一个字典,其中,各省份信息储存在'children'里面
chinaData = areaData[0];
# 取出各省份信息,是一个列表
provinces = chinaData['children'];
print('总共有%d个省份,包括' % len(provinces));
for province in provinces:
	print(province['name']);
总共有34个省份,包括
湖北
广东
浙江
河南
湖南
安徽
江西
江苏
重庆
山东
四川
北京
黑龙江
上海
福建
陕西
河北
广西
云南
海南
山西
辽宁
贵州
天津
甘肃
吉林
内蒙古
宁夏
新疆
香港
青海
台湾
澳门
西藏

以湖北省为例,每一个省份又是一个字典,包含该省每个城市的信息。

Hubei = provinces[0];

city = [];
province = [];
total_confirm = [];
total_dead = [];
total_heal = [];
total_deadRate = [];
total_healRate = [];
for c in Hubei['children']:
    # 城市名称
    city.append(c['name']);
    # 确诊总数
    total_confirm.append(c['total']['confirm']);
    # 治愈总数
    total_heal.append(c['total']['heal']);
    # 死亡总数
    total_dead.append(c['total']['dead']);
    # 总体死亡率
    total_deadRate.append(c['total']['deadRate']);
    # 总体治愈率
    total_healRate.append(c['total']['healRate']);

Hubei_info = pd.DataFrame({'city': city, 'confirm': total_confirm, 'heal': total_heal, 'dead': total_dead, 'healRate(%)': total_healRate, 'deadRate(%)': total_deadRate});

print(Hubei_info);
     city  confirm  heal  dead  healRate(%)  deadRate(%)
0      武汉    14982   877   608         5.85         4.06
1      孝感     2436    45    29         1.85         1.19
2      黄冈     2141   135    43         6.31         2.01
3      荆州      997    40    13         4.01         1.30
4      襄阳      988    40     7         4.05         0.71
5      随州      984    23     9         2.34         0.91
6      黄石      760    54     2         7.11         0.26
7      宜昌      711    36     8         5.06         1.13
8      荆门      663    48    19         7.24         2.87
9      鄂州      639    42    21         6.57         3.29
10     咸宁      493    23     4         4.67         0.81
11     十堰      467    40     0         8.57         0.00
12     仙桃      379    16     5         4.22         1.32
13     天门      197     1    10         0.51         5.08
14    恩施州      171    20     0        11.70         0.00
15     潜江       82     2     2         2.44         2.44
16    神农架       10     2     0        20.00         0.00
17  地区待确认        0     3     0          NaN          NaN

通过类似的操作,现在直接将整个中国的数据转化成dataframe进行输出,代码如下:

city = [];
province = [];
total_confirm = [];
total_dead = [];
total_heal = [];
total_deadRate = [];
total_healRate = [];

for p in provinces:
    for c in p['children']:
        # 省份名称
        province.append(p['name']);
        # 城市名称
        city.append(c['name']);
        # 确诊总数
        total_confirm.append(c['total']['confirm']);
        # 治愈总数
        total_heal.append(c['total']['heal']);
        # 死亡总数
        total_dead.append(c['total']['dead']);
        # 总体死亡率
        total_deadRate.append(c['total']['deadRate']);
        # 总体治愈率
        total_healRate.append(c['total']['healRate']);

china_info = pd.DataFrame({'city': city, 'province': province, 'confirm': total_confirm, 'heal': total_heal, 'dead': total_dead, 'healRate(%)': total_healRate, 'deadRate(%)': total_deadRate});

print(china_info);
      city province  confirm  heal  dead  healRate(%)  deadRate(%)
0       武汉       湖北    14982   877   608         5.85         4.06
1       孝感       湖北     2436    45    29         1.85         1.19
2       黄冈       湖北     2141   135    43         6.31         2.01
3       荆州       湖北      997    40    13         4.01         1.30
4       襄阳       湖北      988    40     7         4.05         0.71
..     ...      ...      ...   ...   ...          ...          ...
421     西宁       青海       15     3     0        20.00         0.00
422    海北州       青海        3     0     0         0.00         0.00
423  地区待确认       台湾       18     1     0         5.56         0.00
424  地区待确认       澳门       10     1     0        10.00         0.00
425  地区待确认       西藏        1     0     0         0.00         0.00

[426 rows x 7 columns]

检查每列的数据类型

print(china_info.info());
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 426 entries, 0 to 425
Data columns (total 7 columns):
city           426 non-null object
province       426 non-null object
confirm        426 non-null int64
heal           426 non-null int64
dead           426 non-null int64
healRate(%)    417 non-null float64
deadRate(%)    417 non-null float64
dtypes: float64(2), int64(3), object(2)
memory usage: 23.4+ KB
None

最后,将其他国家的数据作为一个整体,用dataframe输出

foreign_country = [];
foreign_confirm = [];
foreign_dead = [];
foreign_heal = [];
foreign_deadRate = [];
foreign_healRate = [];

for i in range(1, len(areaData)):
    # 国名
    foreign_country.append(areaData[i]['name']);
    # 确认总数
    foreign_confirm.append(areaData[i]['total']['confirm']);
    # 死亡总数
    foreign_dead.append(areaData[i]['total']['dead']);
    # 治愈总数
    foreign_heal.append(areaData[i]['total']['heal']);
    # 总体死亡率
    foreign_deadRate.append(areaData[i]['total']['deadRate']);
    # 总体治愈率
    foreign_healRate.append(areaData[i]['total']['healRate']);

foreigns = pd.DataFrame({'country': foreign_country, 'confirm': foreign_confirm, 'dead': foreign_dead, 'heal': foreign_heal, 'deadRate': foreign_deadRate, 'healRate': foreign_healRate});

print(foreigns);
   country  confirm  dead  heal  deadRate  healRate
0       中国    37263   813  2767      2.18      7.43
1       日本       89     0     1      0.00      1.12
2      新加坡       40     0     2      0.00      5.00
3       泰国       32     0     8      0.00     25.00
4       韩国       25     0     3      0.00     12.00
5     马来西亚       17     0     2      0.00     11.76
6     澳大利亚       15     0     5      0.00     33.33
7       越南       14     0     3      0.00     21.43
8       德国       13     0     0      0.00      0.00
9       美国       12     0     1      0.00      8.33
10      法国       11     0     0      0.00      0.00
11     加拿大        7     0     0      0.00      0.00
12     阿联酋        7     0     0      0.00      0.00
13      英国        3     0     0      0.00      0.00
14     菲律宾        3     1     0     33.33      0.00
15     意大利        3     0     0      0.00      0.00
16      印度        3     0     0      0.00      0.00
17     俄罗斯        2     0     0      0.00      0.00
18      芬兰        1     0     1      0.00    100.00
19    斯里兰卡        1     0     1      0.00    100.00
20     西班牙        1     0     0      0.00      0.00
21      瑞典        1     0     0      0.00      0.00
22     柬埔寨        1     0     0      0.00      0.00
23     尼泊尔        1     0     0      0.00      0.00
24     比利时        1     0     0      0.00      0.00

检查每一列的数据类型

print(foreigns.info());
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 25 entries, 0 to 24
Data columns (total 6 columns):
country     25 non-null object
confirm     25 non-null int64
dead        25 non-null int64
heal        25 non-null int64
deadRate    25 non-null float64
healRate    25 non-null float64
dtypes: float64(2), int64(3), object(1)
memory usage: 1.3+ KB
None

至此,我们将所需数据存入三个DataFrame中

  • 中国疫情历史数据:chinaDayData
  • 中国各省份城市的当天疫情数据:china_info
  • 其他发生疫情的国家整体疫情数据:foreigns

步骤三:可视化

抱歉,这里请转到大佬@Hakuna_Matata_001的博文,大佬的博文里用到pyecharts,可以作出地图,非常棒,但是本人目前运行pyecharts遇到问题,暂时无法解决,等后面定补上pyecharts的内容!抱拳!~

发布了2 篇原创文章 · 获赞 0 · 访问量 257

猜你喜欢

转载自blog.csdn.net/qq_30841655/article/details/104226413