我用 Python 做了一个全球疫情数据大屏

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 我用 Python 做了一个全球疫情数据大屏

也给我们带来了不少的损失,与此同时我们也认识到在大自然面前人类的渺小。好在在政府的正确且有力的领导下,经过全国人民群众的不懈努力,我们终于将疫情给遏制住了,打赢了这场没有硝烟的战争。


然而就在国内疫情已经明显好转,实现确诊病例零增长的时候,疫情开始在全球蔓延。今天,我用 Python 做了一个全球疫情数据大屏,我们一起来看下整体的效果图。


image.png


整个大屏分为全球数据和国内数据两个模块,每个模块总体分为三个部分,左侧是各个地区详细数据,中间是疫情数据地图,右边则是排行榜和最新动态。


项目结构

我们整个项目的结构图如下所示。


image.png



爬虫模块负责从腾讯新闻获取数据,之后存入 Redis。Flask 是一个 Web 框架,负责 URL 和后台函数的映射,以及数据的传输。换言之,也就是从 Redis 中获取到原始数据,然后整理成相应的格式之后传递给前端页面,前端页面在拿到数据之后,调用百度的 ECharts 来实现图表的展示即可。


引入项目所需的全部模块。


import requests
import json
import redis
from flask import Flask, render_template
import datetime
import pandas as pd


数据获取

开始操作之前,需要先梳理下我们都需要什么数据。关于国内,我们需要的是各个省详细数据、全国数据总和、最新动态、以及境外输入人数 TOP 10 的省市。关于国外,我们需要的是各个国家详细数据、国外数据总和、最新动态、以及 24 小时新增人数 TOP 10 的国家。


本次我们的疫情数据是从腾讯新闻获取的,打开该网址


https://news.qq.com/zt2020/page/feiyan.htm#/?nojump=1)按 F12 将开发者工具调出来,然后切换到 Network 选项页,逐个接口分析之后,发现所有我们想要的数据都是接口返回的。各个数据接口如下:



找到了接口之后,接下来就很简单了,直接调用接口将数据爬取下来即可。其中国内统计数据接口接口返回的 data 不是标准的 JSON 串,而是一个字符串,所以我们需要做下简单的转化。



为了方便h后续操作,我们将调用 request 库爬取数据的操作封装起来,方便调用。


def pull_data_from_web(url):
    response = requests.get(url, headers=header)
    return json.loads(response.text) if response.status_code == 200 else None


最新动态数据我们只取发布时间,标题以及链接地址。


# 获取最新动态数据
# 获取最新动态数据
def get_article_data():
    data = pull_data_from_web('https://api.inews.qq.com/newsqa/v1/automation/modules/list?modules=FAutoNewsArticleList')
    if data is None:
        return ''
    return [[item['publish_time'], item['url'], item['title']] for item in data['data']['FAutoNewsArticleList']]


国内数据我们需要获取数据总和以及各省份详细数据。


# 获取国内统计数据【现有确诊 确诊 治愈 死亡 境外输入 & 各省份详细数据(现有确诊 确诊 治愈 死亡 境外输入)】
def get_china_data():
    data = pull_data_from_web('https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5')
    if data is None:
        return ''
    dict = json.loads(data['data'])
    province_res = []
    for province in dict['areaTree'][0]['children']:
        name = province['name']
        now_confirm = province['total']['nowConfirm']
        confirm = province['total']['confirm']
        heal = province['total']['heal']
        dead = province['total']['dead']
        import_abroad = 0
        for item in province['children']:
            if item['name'] == '境外输入':
                import_abroad = item['total']['confirm']
                break
        province_res.append([name, import_abroad, now_confirm, confirm, heal, dead])
    return {'chinaTotal': dict['chinaTotal'], 'chinaAdd': dict['chinaAdd'], 'province': province_res}


获取国外各个国家及地区详细数据。


# 获取各个国家当前【新增、确诊、治愈、死亡】数据
def get_rank_data():
    data = pull_data_from_web('https://api.inews.qq.com/newsqa/v1/automation/foreign/country/ranklist')
    if data is None:
        return ''
    return [[item['name'], item['confirmAdd'], item['confirm'], item['heal'], item['dead']] for item in data['data']]


国外数据总和。


# 获取国外统计数据【现有确诊 确诊 治愈 死亡】
def get_foreign_data():
    data = pull_data_from_web('https://api.inews.qq.com/newsqa/v1/automation/modules/list?modules=FAutoGlobalStatis')
    if data is None:
        return ''
    return data['data']['FAutoGlobalStatis']


将数据存入 Redis 后就这一步就大功告成了。


article_data = get_article_data()
r.set('article_data', json.dumps(article_data))
rank_data = get_rank_data()
r.set('rank_data', json.dumps(rank_data))
china_data = get_china_data()
r.set('china_data', json.dumps(china_data))
foreign_data = get_foreign_data()
r.set('foreign_data', json.dumps(foreign_data))


数据处理

获取到源数据之后,需要对数据做一下整理,以符合前端页面的展示要求。


整理数据时我们用的是 pandas 这个库,在我们 100 天系列的文章中有做过介绍,忘记的小伙伴们可以翻翻历史文章复习下。


最新动态的数据是比较规整的,不需要做太多处理,直接拿来用即可。


image.png


再看国内的统计数据以及各省份详细数据。


image.png


可回看出当前国内的数据总和是在 chinaTotal 中,当日新增在 chinaAdd 中,各省市详细数据在 province 中,其中各省市详细数据中是按照境外输入、当前确诊、累计确诊、治愈、死亡来存放的。


对于各个省市详细数据,我们以当前确诊人数倒序排序。



image.png


可以看的,现在湖北的确诊人数已经非常少了,而鸡头黑龙江则稳居第一,成为国内确诊人数 TOP 1 的省份。


最后来看国外数据,统计数据比较规整,各个国家详细数据我们按照累计确诊人数倒序排序。


image.png


最后,我们还需要处理下「境外输入省市 TOP 10」和「24小时新增国家 TOP 10」的数据。直接从省市详细数据和各国家详细数据中获取即可。


image.png


图表展示

我们先来简单看下 ECharts 的使用方法,首先要引入相应的 js 文件,然后写一个容纳图表的 div 标签。


<script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script>
<div id="top10" style="width: 300px;height:300px"></div>


最后编写图表的 js 代码即可。


<script type="text/javascript">
    var top10 = echarts.init(document.getElementById('top10'));
    // 指定图表的配置项和数据
    var option = {
        title: {
            text: '测试图表',
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
        },
        xAxis: {
            show: true,
        },
        yAxis: {
            type: 'category',
            data: ['苹果', '橘子', '香蕉', '石榴'],
        },
        series: [
            {
                name: '',
                type: 'bar',
                barWidth: 10,
                data: [66, 88, 90, 20]
            }
        ]
    };
    top10.setOption(option);
</script>



image.png


但这里的数据是固定的,而我们的大屏展示数据都是动态变换的,怎么办呢,前端通过 Ajax 技术从后台接口获取即可,类似下面这样子。


var top10_result = $.ajax({type : "GET", url : 'http://127.0.0.1:5200/china_top10', data : null, async : false});
top10_result = JSON.parse(top10_result.responseText);
// 设置数据
yAxis: {
    type: 'category',
    data: top10_result.country,
},


现在我们已经完成了一个简单的图表,并且已经可以动态设置数据了。现在缺少的就是把大屏的各个图表拼接起来,并且将我们之前准备好的数据设置进去即可

首先我们初始化 Flask 并设置路由映射关系,然后将前端页面所需的统计数据一并返回。


app = Flask(__name__)
@app.route('/global')
def global_index():
    context = {
        'date': get_date(),
        'statistics_data': json.loads(r.get('foreign_data')),
        'country_data': get_rank_data(),
        'article_data': json.loads(r.get('article_data'))
    }
    return render_template('global.html', **context)


其中地图数据以及 TOP 10 的数据需要以接口的方式提供出去,前端页面直接通过 Ajax 技术调用。


@app.route('/global_top10')
def get_global_top10():
    df = pd.DataFrame(json.loads(r.get('rank_data')), columns=['name', 'confirmAdd', 'confirm', 'heal', 'dead'])
    top10 = df.sort_values('confirmAdd', ascending=True).tail(10)
    result = {'country': top10['name'].values.tolist(), 'data': top10['confirmAdd'].values.tolist()}
    return json.dumps(result)
@app.route('/global_map')
def get_global_map():
    df = pd.DataFrame(json.loads(r.get('rank_data')), columns=['name', 'confirmAdd', 'confirm', 'heal', 'dead'])
    records = df.to_dict(orient="records")
    china_data = json.loads(r.get('china_data'))
    result = {
        'confirmAdd': [{'name': '中国', 'value': china_data['chinaAdd']['confirm']}],
        'confirm': [{'name': '中国', 'value': china_data['chinaTotal']['confirm']}],
        'heal': [{'name': '中国', 'value': china_data['chinaTotal']['heal']}],
        'dead': [{'name': '中国', 'value': china_data['chinaTotal']['dead']}]
    }
    for item in records:
        result['confirmAdd'].append({'name': item['name'], 'value': item['confirmAdd']})
        result['confirm'].append({'name': item['name'], 'value': item['confirm']})
        result['heal'].append({'name': item['name'], 'value': item['heal']})
        result['dead'].append({'name': item['name'], 'value': item['dead']})
    return json.dumps(result)

至此,我们完成了从获取数据,到整理数据,再到前端页面展示的整一个过程,还是需要很多知识的。


总结

今天我们完成了一个全球疫情数据大屏可视化程序,步骤清晰,难度不大,只是页面上各个图表组件的位置以及样式调试起来比较繁琐些,但这不是本文重点。


你需要着重理解的是前端页面的 URL 是如何和后台函数做路由映射的,数据又是如何传递和绑定的,以及后台逻辑和数据的处理过程这才是 Web 开发的精髓。


最后,你可以从公众号获取源码后,修改程序使之支持定时从数据源获取数据,更新前端图表,而无需手动操作。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
使用Python实现深度学习模型:智能数据隐私保护
使用Python实现深度学习模型:智能数据隐私保护 【10月更文挑战第3天】
98 0
|
22天前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
7天前
|
图形学 Python
SciPy 空间数据2
凸包(Convex Hull)是计算几何中的概念,指包含给定点集的所有凸集的交集。可以通过 `ConvexHull()` 方法创建凸包。示例代码展示了如何使用 `scipy` 库和 `matplotlib` 绘制给定点集的凸包。
16 1
|
8天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
8天前
|
数据采集 Web App开发 iOS开发
如何使用 Python 语言的正则表达式进行网页数据的爬取?
使用 Python 进行网页数据爬取的步骤包括:1. 安装必要库(requests、re、bs4);2. 发送 HTTP 请求获取网页内容;3. 使用正则表达式提取数据;4. 数据清洗和处理;5. 循环遍历多个页面。通过这些步骤,可以高效地从网页中提取所需信息。
|
1月前
|
数据处理 Python
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
这篇文章介绍了如何使用Python读取Excel文件中的数据,处理后将其保存为txt、xlsx和csv格式的文件。
45 3
Python实用记录(十):获取excel数据并通过列表的形式保存为txt文档、xlsx文档、csv文档
|
1月前
|
计算机视觉 Python
Python实用记录(九):将不同的图绘制在一起、将不同txt文档中的数据绘制多条折线图
这篇文章介绍了如何使用Python的OpenCV库将多张图片合并为一张图片显示,以及如何使用matplotlib库从不同txt文档中读取数据并绘制多条折线图。
41 3
Python实用记录(九):将不同的图绘制在一起、将不同txt文档中的数据绘制多条折线图
|
1月前
|
数据可视化 算法 Python
基于OpenFOAM和Python的流场动态模态分解:从数据提取到POD-DMD分析
本文介绍了如何利用Python脚本结合动态模态分解(DMD)技术,分析从OpenFOAM模拟中提取的二维切片数据,以深入理解流体动力学现象。通过PyVista库处理VTK格式的模拟数据,进行POD和DMD分析,揭示流场中的主要能量结构及动态特征。此方法为研究复杂流动系统提供了有力工具。
63 2
基于OpenFOAM和Python的流场动态模态分解:从数据提取到POD-DMD分析
|
21天前
|
数据可视化 算法 JavaScript
基于图论的时间序列数据平稳性与连通性分析:利用图形、数学和 Python 揭示时间序列数据中的隐藏模式
本文探讨了如何利用图论分析时间序列数据的平稳性和连通性。通过将时间序列数据转换为图结构,计算片段间的相似性,并构建连通图,可以揭示数据中的隐藏模式。文章介绍了平稳性的概念,提出了基于图的平稳性度量,并展示了图分区在可视化平稳性中的应用。此外,还模拟了不同平稳性和非平稳性程度的信号,分析了图度量的变化,为时间序列数据分析提供了新视角。
48 0
基于图论的时间序列数据平稳性与连通性分析:利用图形、数学和 Python 揭示时间序列数据中的隐藏模式
|
29天前
|
自然语言处理 算法 数据挖掘
探讨如何利用Python中的NLP工具,从被动收集到主动分析文本数据的过程
【10月更文挑战第11天】本文介绍了自然语言处理(NLP)在文本分析中的应用,从被动收集到主动分析的过程。通过Python代码示例,详细展示了文本预处理、特征提取、情感分析和主题建模等关键技术,帮助读者理解如何有效利用NLP工具进行文本数据分析。
45 2