爬虫数据清洗可视化案例之全球灾害数据

目标网站: 全球灾害数据平台
温馨提示: 仅供学习交流使用

|----------------|-------------|
| requests() | lxml |
| pandas | numpy |
| matplotlib | seaborn |
| pprint | |
[本案例所使用的库]

明确需要爬取的内容:

国家地区

所属洲

总频次

受影响人口(万人)

死亡人口(人)

经济损失(千美元)

爬取步骤:

发送请求 模拟浏览器向服务器 发送请求

解析数据 提取想要的数据

保存数据 持久化保存 csv excel 数据库

一.发送请求

确定网页的构造 静态数据 or 动态数据
右击查看网页源代码 Ctrl+F 再搜索框中输入要获取的信息

返回的结果是没有 说明是动态的数据 需要抓包分析

此时 到网页主界面 快捷键(F12) or 右击 检查

点击网络 接着刷新当前界面 或 Ctrl+R(快捷键刷新)

同样地 Ctrl+F 打开搜索框 输入想获取的数据 在返回中的数据包中筛选 找到符合的那个

然后 点击标头 这里有请求的一些基本信息 可以查看

我们使用爬虫工具 快速构建 爬虫请求代码

右击相应的数据包 点击复制cURL(bash) 如上图所示 注意是bash

之后打开 工具 爬虫工具库-spidertools.cn

复制右边的代码 到Pycharm中

运行代码 检查想爬取的数据是否在返回的数据中

二. 解析数据

因为返回的是Json格式的数据 需要获取 返回的Json

这里我们可以使用 python 模块 pprint 可以让Json 格式的数据更加美观

python 复制代码
import pprint


pprint.pprint(response.json())

这样输出就会如下图所示

对比页面 找到想要爬取数据的位置 字段名

接着我们从 字典套列表的格式中提取数据 通过键值对取值 For循环遍历列表 取值

python 复制代码
json_data = response.json()['data']['content']


# 拿到想要的数据
for li in json_data:
    country = li['countryCn']
    state = li['continentCn']
    total = li['sum']
    death_people = li['death']
    influence_people = li['population']
    found_lose = li['loss']


# 可以输出打印 对比数据是否符合

三. 保存数据

保存数据为 Excel文件

python 复制代码
# 先将数据存储到 字典中
# 再定义一个列表  将数据添加进去
dit = {
        '国家': country,
        '州': state,
        '总频次': total,
        '死亡人数': death_people,
        '影响人数': influence_people,
        '损失': found_lose
    }

# 保存数据 为excel
pd.DataFrame(lis).to_excel('global_disaster.xlsx',index=False)

多页爬取 查看请求体里面的data参数 直接 修改 循环即可 我这里写它全部的数据

温馨提示: 它这个 "Authorization" 参数具有时效性 逆向可解决 但不影响我们获取数据

这样就爬取到了我们想要的数据

以下是爬虫部分的全部代码

python 复制代码
import pprint

import pandas as pd
import requests
import json

headers = {
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "Authorization": "Bearer b81b81e2-da54-4548-ac4f-4504ba437b51",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Content-Type": "application/json;charset=UTF-8",
    "Origin": "https://www.gddat.cn",
    "Pragma": "no-cache",
    "Referer": "https://www.gddat.cn/newGlobalWeb/",
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0",
    "sec-ch-ua": "\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\""
}
cookies = {
    "你的cookie"
}
url = "https://www.gddat.cn/gw/application-base-ris-portal/featureAnalysis/idisasterEmdatStandard/getIHistoryByCountry"
data = {
    "continentCn": "",
    "frequency": "10",
    "continent": [],
    "countryCode": [],
    "eventTypeCode": [],
    "maxaffected": "",
    "maxdeaths": "",
    "maxloss": "",
    "minaffected": "",
    "mindeaths": "",
    "minloss": "",
    "orderby": "sum",
    "fromYear": "",
    "toYear": "",
    "Year": "",
    "page": 0,
    "size": 204,
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, cookies=cookies, data=data)

lis = []
json_data = response.json()['data']['content']
for li in json_data:
    country = li['countryCn']
    state = li['continentCn']
    total = li['sum']
    death_people = li['death']
    influence_people = li['population']
    found_lose = li['loss']

    dit = {
        '国家': country,
        '州': state,
        '总频次': total,
        '死亡人数': death_people,
        '影响人数': influence_people,
        '损失': found_lose
    }
    lis.append(dit)

pd.DataFrame(lis).to_excel('global_disaster.xlsx',index=False)

数据清洗:

这里我们选择直接将缺失值删除

python 复制代码
import pandas as pd

# 读取文件
df = pd.read_excel('global_disaster.xlsx')

# 将损失为缺失值的国家名字 展示出来
country_lose = df[df['损失'].isna()]['国家'].tolist()
# 删除缺失值
df.dropna(subset='损失', inplace=True)

# 统计缺失值的数量
total = df['损失'].isna().sum()
# 展示处理后的前五条记录
print(df.head())

python 复制代码
state_num = df['州'].unique()

没有不符合要求的命名


python 复制代码
# iqr 处理异常值
lo = df['死亡人数'].quantile(0.25)
up = df['死亡人数'].quantile(0.75)
iqr = up - lo
lower = lo - 1.5 * iqr
upper = up + 1.5 * iqr

# 未清理前的数据长度
before_clean = len(df)

# df = df[(df['死亡人数'] > lower) & (df['死亡人数'] < upper)]
# 异常值 展示
# 异常值
false_death = df[(df['死亡人数'] < lower) | (df['死亡人数'] > upper)]
df['死亡人数'] = np.where(
    (df['死亡人数'] < lower) | (df['死亡人数'] > upper),
    None,
    df['死亡人数']
)

df.dropna(subset='死亡人数',inplace=True)

print(len(df))

# 思路是 将异常值用None值代替  后续删除

python 复制代码
df['影响人数'] = pd.to_numeric(df['影响人数'], errors='coerce')
df['损失'] = pd.to_numeric(df['损失'], errors='coerce')
# print(df.info())
# print(df.head(5))


python 复制代码
duplicated = df.duplicated().sum()
df.drop_duplicates(inplace=True)

# print(len(df))

python 复制代码
df['损失'] = (df['损失'] / 1000000).round(2)
print(df.head())


python 复制代码
consistent_check = df[(df['总频次'] == 0) & (df['死亡人数'] > 0)]

print(consistent_check)

数据可视化:

画出各州灾害总频次热力图 经济损失热力图 死亡人数热力图 平均灾害频次热力图

python 复制代码
# 导包
import matplotlib.pyplot as plt
from matplotlib import rcParams
import seaborn as sns
import pandas as pd

df = pd.read_excel('cleaned_global_disaster.xlsx')

# 设置字体 为默认的黑体
rcParams['font.family'] = 'SimHei'

region_summery = df.groupby(['州']).agg({
    '总频次': 'sum',
    '死亡人数': 'sum',
    '损失': 'sum',
    '国家': 'count',
}).rename(columns={'国家': '国家数量', '损失': '损失(万元)'}).sort_values(by=['总频次', '损失(万元)'],
                                                                          ascending=[False, False])

# 画子图
plt.subplot(2, 2, 1)
# annot = True  表示在热力图中显示对应的数值
# fmt = '.0f' 表示将数值类型的格式化为整数
# colormap的缩写 cmap   指定用红色系的颜色映射  Reds
# 设置cbar_Kws 用于设置颜色条的属性
# shrink 用于设置颜色条的大小
# annot_kws 用于设置注解的属性 字体 大小
# linewidths  设置单元格边框
sns.heatmap(region_summery[['总频次']], annot=True, fmt='.0f', cmap='Reds', linewidths=0.5,
            annot_kws={'size': 12, 'weight': 'bold'}, cbar_kws={'label': '灾害频次', 'shrink': 0.8})
plt.title('各州灾害总频次热力图')

plt.subplot(2, 2, 2)
sns.heatmap(region_summery[['损失(万元)']],
            annot=True,
            annot_kws={'size': 12, 'weight': 'bold'},
            linewidths=0.5,
            fmt='.0f',
            cmap='Oranges',
            cbar_kws={'label': '损失(百万美元)', 'shrink': 0.8}
            )

plt.title('各州经济损失热力图')

plt.subplot(2, 2, 3)
sns.heatmap(region_summery[['死亡人数']],
            annot=True,
            annot_kws={'size': 12, 'weight': 'bold'},
            linewidths=0.5,
            fmt='.0f',
            cmap='Purples',
            cbar_kws={'label': '死亡人数', 'shrink': 0.8}
            )
plt.title('各州死亡人数热力图')

plt.subplot(2, 2, 4)

region_summery['平均频次'] = region_summery['总频次'] / region_summery['国家数量']
sns.heatmap(region_summery[['平均频次']],
            annot=True,
            annot_kws={'size': 12, 'weight': 'bold'},
            fmt='.1f',
            cmap='Blues',
            linewidths=0.5,
            cbar_kws={'label': '平均灾害频次', 'shrink': 0.8}
            )
plt.title('各州平均灾害频次热力图')

plt.tight_layout()
plt.show()
# print(region_summery)

如下图:

本次的案例分享到此结束 如果觉得还不错 你的点赞关注是我更新进步的动力 谢谢!

相关推荐
默_笙1 天前
🍙 给每个请求过安检:FastAPI 是怎么把校验写进类型注解的
python
qq_426003961 天前
启动playwright录制codegen生成自动化测试脚本
python·自动化
虎头金猫1 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
长沙三为智能科技1 天前
家政小程序开发从0到上线:五阶段交付流程与验收清单
python
伞伞悦读1 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
龙亘川1 天前
明月照湾区,智启新赛道:从顶流文旅IP盛会看智慧文旅升级路径
人工智能·智慧城市·开源软件·数据可视化
只睡四小时1 天前
Canvas 弹道联机实战:700 行 + 固定时间步长
python·websocket·html5·游戏开发·canvas
龙亘川1 天前
一网统管AI平台民生业务实践:基于城市数字底座赋能公积金业务服务升级
大数据·安全·智慧城市·开源软件·数据可视化·政务
奇思妙想聪明勤奋的小羊1 天前
DeepAgents第5章:子Agent 与上下文隔离—让 Agent学会委派
人工智能·python·学习·语言模型
lpfasd1231 天前
2026年第38周GitHub趋势周报
python·科技·github