【疫情监控】打造全国新冠疫情Web项目:三次优化,提升用户体验

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本文分享了开发全国新冠疫情Web项目的经验和优化过程,包括调整项目结构、新增logger模块改善日志记录、实现数据实时刷新功能,以及通过spider模块代码自动更新疫情数据,提升了用户体验并简化了项目维护流程。

日拱一卒无有尽,功不唐捐终入海!

一、背景

在整理公司项目的时候 ,不晓得什么时候接了一个关于疫情的项目,需要可视化展示数据 ,大致了解过项目结构和实现逻辑,先是从公共接口爬取数据,然后清洗数据再写入数据库,最后使用flask后台框架启动访问web,读取数据库的数据,经过前端渲染,如下图所示:

在这里插入图片描述

1.1、调整原来的项目结构

在这里插入图片描述

新增了conf目录,作为该项目的数据配置项,譬如mysql信息就统一管理,因为原项目在spider和sqldata两处都创建了mysql连接,所以只保留一处即可

def mysql():
    """创建mysql连接,返回数据库操作对象"""
    db = pymysql.connect(host=MYSQL_HOST, user=MYSQL_DB_USER, password=MYSQL_DB_PASSWORD, database=MYSQL_DB_NAME, charset='utf8')
    cur = db.cursor()
    return db, cur


def close(db, cur):
    """关闭数据库连接"""
    cur.close()
    db.close()


def query(sql: str, *args):
    """执行sql并返回结果"""
    db, cur = mysql()
    cur.execute(sql, args)
    result = cur.fetchall()
    close(db, cur)
    return result

二、新增/优化功能

原项目中在spider文件中,每次操作都会在控制台输出print日志,这个样子有点不美观

在这里插入图片描述

2.1、新增logger模块

创建libs作为整个项目的工具类

class Logger(object):
    __instance = None

    def __new__(cls, *args, **kwargs):
        if not cls.__instance: 
            cls.__instance = object.__new__(cls, *args) 
        return cls.__instance 

    def __init__(self):
        self.formater = logging.Formatter(
            '[%(asctime)s] [%(levelname)s] [%(module)s:%(lineno)d ], %(message)s')
        self.logger = logging.getLogger('log')
        self.logger.setLevel(logging.DEBUG)
        self.filelogger = handlers.RotatingFileHandler(LOG_PATH,
                                                       maxBytes=5242880,
                                                       backupCount=3,
                                                       encoding='utf-8')
        # self.console = logging.StreamHandler()
        # self.console.setLevel(logging.DEBUG)
        self.filelogger.setFormatter(self.formater)
        # self.console.setFormatter(self.formater)
        self.logger.addHandler(self.filelogger)
        # self.logger.addHandler(self.console)
  • 日志输出乱码?

在文件处理对象的时候,需要指定encoding=‘utf-8’,避免乱码

2.2、实时刷新数据

前面读了spider模块,每次执行都会先删除表然后再创建最后写入数据,从数据库配置来看完全没有任何压力,但是启动app时,它并没有刷新数据库,每次都会获取第一次执行spider的数据,所以需要做到实时刷新,也就是spider需要每次都执行。

@app.route('/')
def hello_world():
    logger.logger.info("用来刷新数据...")
    main() # 这个就是每次操作数据库,删除、创建、写入
    return render_template('main.html')

三、总结

就整个项目而言,原先是需要先执行spider然后再启动app,所以没那么智能,在经过调整后,只需要启动app就会连带讲数据库的数据刷新一遍,每次都会是最新数据,尽管是每天的某个固定时间才会更新,总好过每次手动指定spider模块;

  • 还有一点优化,就是requirements.txt;在当前环境安装pipreqs,然后在工程根路径下执行pipreqs ./就可以获得项目相关的库依赖,这样就方便项目迁移了。

附录spider模块代码<关注我,获取源码>:

def get_json(url):
    headers = {
   
   
        'user - agent': 'Mozilla / 5.0(WindowsNT10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 80.0.3987.116Safari / 537.36'
    }
    response = requests.get(url=url, headers=headers).text
    data = json.loads(response)
    return data['data']


# 获取当日数据
def get_now(data):
    now = []
    data_time = str(data['diseaseh5Shelf']['lastUpdateTime'])  # 数据更新时间
    data_all = data['diseaseh5Shelf']['areaTree'][0]
    data_province_s = data['diseaseh5Shelf']['areaTree'][0]['children']

    # 获取全国今日新增、累计确诊、治愈人数、死亡人数
    confirms = data_all['total']['confirm']
    confirms_add = data_all['today']['confirm']
    heals = data_all['total']['heal']
    deads = data_all['total']['dead']

    # 获取每个省份的每个城市今日新增、累计确诊、治愈人数、死亡人数
    for data_province in data_province_s:
        province = data_province['name']  # 省份
        for data_city in data_province['children']:
            city = data_city['name']  # 城市
            confirm = data_city['total']['confirm']  # 确诊
            confirm_add = data_city['today']['confirm']  # 新增
            heal = data_city['total']['heal']  # 治愈
            dead = data_city['total']['dead']  # 死亡
            now.append((data_time, province, city, confirm_add, confirm, heal, dead))
    return confirms, confirms_add, heals, deads, now


# 获取历史数据
def get_past(data):
    past = {
   
   }
    for data_day in data:
        data_time = data_day['date']  # 获取最原始的时间
        time_deal = time.strptime(data_time, '%m.%d')  # 根据指定的格式把一个时间字符串解析为时间元组
        date = time.strftime('%m-%d', time_deal)  # 重新组成新的时间字符串
        past[date] = {
   
   
            'confirm': data_day['confirm'],  # 确诊
            'suspect': data_day['suspect'],  # 疑似
            'heal': data_day['heal'],  # 治愈
            'dead': data_day['dead']  # 死亡
        }

    return past


# 写入当日数据
def insert_now(now):
    try:
        logger.logger.info("每次这个很有意思,每次刷新都需要先删除数据表,然后再创建表,最后再将清洗的数据写入表中.")
        cur.execute("DROP TABLE IF EXISTS 当日数据")
        # 写创建表的sql语句
        set_sql_now = "create table 当日数据(时间 varchar(100),省份 varchar(50),城市 varchar(50),新增确诊 int(11)," \
                      "确诊人数 int(11),治愈人数 int(11),死亡人数 int(11))ENGINE=InnoDB DEFAULT CHARSET=utf8"
        # 执行sql语句
        cur.execute(set_sql_now)
        # 保存
        db.commit()
        # 写入数据库
        save_sql_now = "insert into 当日数据 values(%s,%s,%s,%s,%s,%s,%s)"
        cur.executemany(save_sql_now, now)  # now位置必须是个列表,列表里面的元素是数组
        db.commit()
        logger.logger.info('当日数据写入成功')
    except Exception as e:
        logger.logger.error('当日数据写入失败原因:%s' % e)


# 写入历史数据
def insert_past(past):
    try:
        cur.execute("DROP TABLE IF EXISTS 历史数据")
        # 写创建表的sql语句
        set_sql_past = "create table 历史数据(时间 varchar(100),确诊人数 int(11),疑似病例 int(11),治愈人数 int(11)," \
                       "死亡人数 int(11))ENGINE=InnoDB DEFAULT CHARSET=utf8"
        # 执行sql语句
        cur.execute(set_sql_past)
        # 保存
        db.commit()
        # 写入历史数据
        for date, data in past.items():
            sql_past = f"insert into 历史数据 values('{date}',{data['confirm']},{data['suspect']},{data['heal']}," \
                       f"{data['dead']})"
            cur.execute(sql_past)
        db.commit()
        logger.logger.info('历史数据写入成功')
    except Exception as e:
        logger.logger.error('历史数据写入失败原因:%s' % e)


# 写入历史新增数据
def insert_past_add(past):
    try:
        cur.execute("DROP TABLE IF EXISTS 历史新增数据")
        # 写创建表的sql语句
        set_sql_past = "create table 历史新增数据(时间 varchar(100),新增确诊 int(11),新增疑似 int(11),新增治愈 int(11)," \
                       "新增死亡 int(11))ENGINE=InnoDB DEFAULT CHARSET=utf8"
        # 执行sql语句
        cur.execute(set_sql_past)
        # 保存
        db.commit()
        # 写入历史数据
        for date, data in past.items():
            sql_past = f"insert into 历史新增数据 values('{date}',{data['confirm']},{data['suspect']},{data['heal']}," \
                       f"{data['dead']})"
            cur.execute(sql_past)
        db.commit()
        logger.logger.info('历史新增数据写入成功')
    except Exception as e:
        logger.logger.error('历史新增数据写入失败原因:%s' % e)


# 写入累计确诊等四个关键数据
def insert_main(confirm, confirm_add, heal, dead):
    try:
        cur.execute("DROP TABLE IF EXISTS 关键数据")
        # 写创建表的sql语句
        set_sql_main = "create table 关键数据(确诊人数 int(11),新增确诊 int(11),治愈人数 int(11),死亡人数 int(11))" \
                       "ENGINE=InnoDB DEFAULT CHARSET=utf8"
        cur.execute(set_sql_main)
        db.commit()
        # 写入确诊人数、新增确诊、治愈人数、死亡人数的数据
        save_sql_main = f"insert into 关键数据 values({confirm},{confirm_add},{heal},{dead})"
        cur.execute(save_sql_main)
        db.commit()
        logger.logger.info('关键数据写入成功')
    except Exception as e:
        logger.logger.error('关键数据写入失败原因:%s' % e)
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
14天前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
25 1
|
14天前
|
Java 开发者 JavaScript
Struts 2 开发者的秘籍:隐藏的表单标签库功能,能否成为你下个项目的大杀器?
【8月更文挑战第31天】Struts 2表单标签库是提升Web页面交互体验的神器。它提供丰富的标签,如`&lt;s:textfield&gt;`和`&lt;s:select&gt;`,简化表单元素创建与管理,支持数据验证和动态选项展示。结合示例代码,如创建文本输入框并与Action类属性绑定,显著提升开发效率和用户体验。通过自定义按钮样式等功能,Struts 2表单标签库让开发者更专注于业务逻辑实现。
38 0
|
14天前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
25 0
|
14天前
|
开发者 安全 SQL
JSF安全卫士:打造铜墙铁壁,抵御Web攻击的钢铁防线!
【8月更文挑战第31天】在构建Web应用时,安全性至关重要。JavaServer Faces (JSF)作为流行的Java Web框架,需防范如XSS、CSRF及SQL注入等攻击。本文详细介绍了如何在JSF应用中实施安全措施,包括严格验证用户输入、使用安全编码实践、实施内容安全策略(CSP)及使用CSRF tokens等。通过示例代码和最佳实践,帮助开发者构建更安全的应用,保护用户数据和系统资源。
27 0
|
14天前
|
前端开发 JavaScript 开发者
JSF与WebSockets,打造实时通信魔法!让你的Web应用秒变聊天室,用户体验飞升!
【8月更文挑战第31天】在现代Web应用开发中,实时通信对于提升用户体验至关重要。本文探讨了如何在主要面向Web应用开发的JSF(JavaServer Faces)框架中引入WebSockets支持,以实现客户端与服务器之间的全双工通信。通过具体示例展示了在JSF应用中实现WebSockets的基本步骤:添加依赖、创建服务器端点以及在前端页面中嵌入JavaScript客户端代码。尽管这一过程中可能会遇到一些挑战,如复杂代码编写和额外配置需求,但借助AWS等云服务平台,开发者仍能高效地完成部署和管理工作,从而增强Web应用的实时通信能力。
20 0
|
14天前
|
开发者 前端开发 开发框架
JSF与移动应用,开启全新交互体验!让你的Web应用轻松征服移动设备,让用户爱不释手!
【8月更文挑战第31天】在现代Web应用开发中,移动设备的普及使得构建移动友好的应用变得至关重要。尽管JSF(JavaServer Faces)主要用于Web应用开发,但结合Bootstrap等前端框架,也能实现优秀的移动交互体验。本文探讨如何在JSF应用中实现移动友好性,并通过示例代码展示具体实现方法。使用Bootstrap的响应式布局和组件可以确保JSF页面在移动设备上自适应,并提供友好的表单输入和提交体验。尽管JSF存在组件库较小和学习成本较高等局限性,但合理利用其特性仍能显著提升用户体验。通过不断学习和实践,开发者可以更好地掌握JSF应用的移动友好性,为Web应用开发贡献力量。
25 0
|
14天前
|
安全 Java 云计算
JSF 应用究竟何去何从?云端部署能否成为其全新突破点?快来一探究竟!
【8月更文挑战第31天】本文介绍了将JavaServer Faces(JSF)应用部署到云平台的过程。首先,根据成本、功能、可靠性和安全性选择合适的云平台。接着,展示了构建简单JSF应用的示例代码。最后,以AWS Elastic Beanstalk为例,详细说明了部署流程。部署至云端可提升应用的可用性、扩展性和安全性。
28 0
|
14天前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
38 0
|
14天前
|
开发者 Java
Play Framework深度解析:依赖注入的神秘力量,如何助力Web应用架构优化?答案即将揭晓!
【8月更文挑战第31天】依赖注入(DI)是现代软件开发的关键技术,用于分离对象创建与依赖关系,提升代码的可维护性和可测试性。Play Framework是一款高性能Java Web框架,内置了基于Google Guice的DI支持。本文探讨Play Framework中DI的最佳实践,包括定义组件、构造函数注入、字段注入以及作用域控制和自定义绑定等高级特性,帮助开发者轻松构建结构清晰、可维护性高的Web应用。
27 0
|
13天前
|
数据库 开发者 Python
web应用开发
【9月更文挑战第1天】web应用开发
33 1