news 2026/4/21 7:24:54

【Python实战解析】从技能大赛样题看疫情数据管理系统的全栈开发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Python实战解析】从技能大赛样题看疫情数据管理系统的全栈开发

1. 从赛题到项目:一个Python全栈开发者的实战视角

大家好,我是老张,一个在Python和智能硬件领域摸爬滚打了十多年的开发者。最近,我仔细研究了一下湖南省职业院校技能大赛Python程序开发赛项的样题,特别是那个关于“疫情数据管理系统”的题目。看完之后,我感触很深。这不仅仅是一套考题,它几乎就是一个完整的、微缩版的真实企业级项目开发流程。从Web后台开发、数据爬取,到数据清洗、处理,再到最后的可视化呈现,整个链路非常清晰。但我也发现,很多新手朋友拿到这样的题目,容易陷入“解题”思维,只想着怎么把代码填空补全,拿个分数。这其实有点可惜。今天,我想换个角度,带大家把这道“样题”当成一个真实的“项目”来从头构建。我们不只追求功能实现,更要思考如何设计代码结构、如何让各个模块优雅地协作、如何写出更健壮、更易维护的代码。我会分享我在实际项目中踩过的坑和总结的经验,目标是让你看完后,不仅能复现这个系统,更能掌握一套应对类似综合性开发任务的完整方法论。

这个项目麻雀虽小,五脏俱全。它要求我们搭建一个具备管理员登录、学生信息增删改查(CRUD)、健康风险筛查等功能的Web后台(第一部分),然后从外部获取疫情数据(第二部分),对这些可能杂乱无章的数据进行清洗和规整(第三部分),再用正则表达式和文件操作进行深度处理(第四部分),最后用图表和词云让数据“说话”(第五部分)。这完全就是一个数据驱动型Web应用的标准开发流程。接下来,我们就抛开“考生”身份,以“项目开发者”的视角,一步步拆解并实现它。我会在每个环节,不仅告诉你题目要求怎么做,更会分享在实际开发中,我们通常会怎么做,以及为什么这么做更好。

2. 项目基石:用Flask快速搭建Web管理后台

2.1 环境准备与项目骨架搭建

工欲善其事,必先利其器。我们首先得把开发环境搭起来。题目中默认使用了Pycharm和MySQL,这很常见。我个人的习惯是使用虚拟环境来隔离项目依赖,避免不同项目间的包版本冲突。你可以打开终端,执行python -m venv venv来创建一个虚拟环境,然后激活它。在项目根目录下,我们创建一个requirements.txt文件,把需要的包列进去。对于这个项目,核心依赖大概是这些:Flask(Web框架)、Flask-SQLAlchemy(ORM工具)、pandas、requests、beautifulsoup4、matplotlib、wordcloud、jieba。你可以用pip install -r requirements.txt一键安装。

接下来是项目结构。一个清晰的结构是后期维护的救命稻草。我建议这样组织:

epidemic_data_system/ ├── app.py # 应用主入口,Flask app创建和路由注册 ├── config.py # 配置文件,数据库连接、密钥等 ├── requirements.txt ├── static/ # 静态文件,CSS, JS, 图片 ├── templates/ # Jinja2模板,HTML页面 ├── models.py # 数据库模型定义(Student, HealthRecord等) ├── views/ # 视图函数(业务逻辑)可以按模块分文件 │ ├── auth.py # 认证相关(登录注销) │ ├── student.py # 学生信息管理 │ └── health.py # 健康风险数据 ├── utils/ # 工具函数 │ ├── data_fetcher.py # 数据爬取模块 │ ├── data_cleaner.py # 数据清洗模块 │ └── visualizer.py # 可视化生成模块 └── data/ # 存放原始数据、处理结果、生成的图片

这样的结构是不是比把所有代码堆在一个文件里清爽多了?在config.py里,我们配置数据库连接,就像题目里给的mysql://root:123456@localhost/epidemic_db。记住,密码千万不要硬编码在代码里,尤其是要提交到GitHub等公开平台时,一定要用环境变量来管理。

2.2 实现核心CRUD与业务逻辑

现在我们聚焦核心功能。题目第一部分要求实现登录、查询、增删改查和风险筛查。我们用Flask和SQLAlchemy来优雅地实现。首先在models.py里定义Student模型,包含学号、姓名、电话、地址、院系、专业等字段。这里有个细节,学号(student_id)字段应该设置unique=Truenullable=False,确保唯一且非空,这是数据完整性的基本保障。

登录功能,题目要求用户名密码都是admin。在实际项目中,我们绝不会这样写死。我会用数据库存储用户信息,并且对密码进行哈希加密(比如用Werkzeug的generate_password_hashcheck_password_hash)。登录视图函数(在views/auth.py中)接收前端POST请求,验证用户名密码,成功后使用flask.session来记录用户登录状态。这是保持用户会话的标准做法。

学生信息的查询、分页和条件过滤,是Web后台的常见需求。题目要求按id降序分页,每页10条。用SQLAlchemy实现起来非常简洁:Student.query.order_by(Student.id.desc()).paginate(page=page, per_page=10, error_out=False)paginate对象包含了当前页的数据、总页数等信息,直接传给模板渲染就行。至于按学号或手机号查询,我建议使用一个搜索框,而不是两个独立的输入框。后端视图函数可以这样处理:获取搜索关键词keyword,然后构造查询Student.query.filter(db.or_(Student.student_id.like(f%{keyword}%), Student.phone.like(f%{keyword}%)))db.or_实现了“或”条件查询,like%通配符实现了模糊匹配,更符合用户习惯。

增删改查(CRUD)的实现,关键在于表单处理和数据库操作。对于新增和编辑,我们需要创建表单类(可以用Flask-WTF扩展,它提供了CSRF保护等安全特性)。处理POST请求时,用form.validate_on_submit()验证数据,然后创建新的Student对象或更新现有对象,最后db.session.commit()。删除操作要谨慎,通常我们会做一个软删除(增加一个is_deleted标记字段)而不是物理删除,但题目要求直接删除,我们就调用db.session.delete(student)

最复杂的可能是“健康风险学生”查询。题目逻辑是:在特定时间段内,有症状、或途径风险区、或体温≥37度。这涉及到多表关联查询(假设健康申报记录在另一个HealthRecord表中)和复杂的过滤条件。SQLAlchemy的查询可以这样构建:

from datetime import datetime start_date = datetime(2021, 12, 2) end_date = datetime(2021, 12, 17, 23, 59, 59) risk_students = db.session.query(Student).join(HealthRecord).filter( HealthRecord.report_time.between(start_date, end_date), db.or_( HealthRecord.has_symptoms == True, HealthRecord.passed_risk_area == True, HealthRecord.temperature >= 37.0 ) ).order_by(HealthRecord.report_time.desc()).all()

这个查询清晰地表达了业务逻辑,可读性和可维护性都比写原生SQL要好。完成这些后,一个具备基本业务功能的Web管理后台就成型了。

3. 数据流水线:从爬取、清洗到规整

3.1 使用Requests与BeautifulSoup高效抓取数据

项目第二部分要求从网页抓取全球疫情数据。题目用了urllib,但在实际开发中,我强烈推荐使用requests库,它的API更加友好和简洁。搭配BeautifulSoup进行HTML解析,是爬虫的黄金组合。首先,我们分析目标网页结构。你需要用浏览器的开发者工具(F12)查看疫情数据表格在HTML中的位置,通常是<table>标签,或者是一些有规律的<div>

utils/data_fetcher.py中,我们定义抓取函数。第一步是发送HTTP请求并处理异常。我会这样写:

import requests from bs4 import BeautifulSoup import time def fetch_epidemic_data(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...' } try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() # 如果状态码不是200,抛出HTTPError异常 response.encoding = response.apparent_encoding # 自动识别编码 return response.text except requests.RequestException as e: print(f"抓取网页时发生错误: {e}") return None

这里加了请求头模拟浏览器,设置了超时,并做了基本的异常捕获,这是生产级代码的基本素养。

拿到HTML后,用BeautifulSoup解析。假设数据在一个id为worldTable的表格里,我们这样提取:

def parse_data(html): if not html: return [] soup = BeautifulSoup(html, 'html.parser') table = soup.find('table', id='worldTable') data_list = [] for row in table.find('tbody').find_all('tr'): cols = row.find_all('td') if len(cols) >= 5: # 确保有足够列 country = cols[0].text.strip() current = cols[1].text.strip().replace(',', '') total = cols[2].text.strip().replace(',', '') deaths = cols[3].text.strip().replace(',', '') cured = cols[4].text.strip().replace(',', '') # 将字符串转换为整数,注意处理空值或非法字符 try: data_list.append([country, int(current), int(total), int(deaths), int(cured)]) except ValueError: print(f"数据转换错误,跳过此行: {country}") continue return data_list

注意,我们从网页上抓取的数字通常带有逗号分隔符,需要先去掉。并且,数据转换时一定要用try-except包裹,因为网页数据可能不规范,避免一个错误导致整个程序崩溃。

3.2 利用Pandas进行专业级数据清洗

抓取到的数据往往是“脏”的,这就是第三部分数据清洗的意义。Pandas是处理这类任务的利器。题目要求处理缺失值、重复值和冗余数据。我们假设数据已经读入一个名为df的DataFrame中。

首先,查看数据概览:df.info()df.head()info()能快速看到每列的非空值数量,从而发现缺失值。处理缺失值有多种策略:对于数值列(如确诊人数),如果缺失不多,可以用均值或中位数填充(df['confirmed'].fillna(df['confirmed'].median(), inplace=True));对于类别列(如省份),如果缺失,可以用众数填充或者直接标记为“未知”;如果某一行缺失值太多,整行删除可能更合适(df.dropna(thresh=3, inplace=True)表示至少要有3个非空值才保留)。

查找和处理重复值:df.duplicated().sum()可以查看有多少完全重复的行。使用df.drop_duplicates(inplace=True)删除它们。但要注意一种情况:某些行可能关键字段(如“国家+日期”)重复,但其他字段不同,这可能是数据错误,需要根据业务逻辑判断如何处理。

数据规整还包括数据类型转换。爬取的数据列很可能都是object(字符串)类型,我们需要将数字列转换为intfloatdf['confirmed'] = pd.to_numeric(df['confirmed'], errors='coerce')errors='coerce'会将无法转换的值设为NaN,方便后续统一处理。

最后,我们可能还需要进行一些衍生计算,比如计算每日新增确诊(用df['confirmed'].diff()),或者计算治愈率(df['cured'] / df['total'])。清洗完成后,将干净的数据保存到新的CSV文件或直接写入数据库,供后续分析使用。这一套流程下来,原始杂乱的数据就变成了规整、高质量的数据集,这是所有数据分析工作的基础。

4. 文本与文件处理:正则表达式与OS模块的妙用

4.1 用正则表达式(re)精准提取文本信息

第四部分的第一题是关于文本处理的,这在实际项目中太常见了,比如从日志文件里提取错误码,或者从非结构化的文本中抽取关键信息。题目要求保留中英文和数字,过滤掉其他字符。正则表达式(regex)是完成这类任务的“手术刀”。

Python的re模块功能强大。我们首先要明确匹配规则:中文字符的Unicode范围是\u4e00-\u9fa5,英文字母是a-zA-Z,数字是0-9。所以,匹配我们想要保留的字符的正则表达式是:[\u4e00-\u9fa5a-zA-Z0-9]+。这里的+表示匹配一个或多个这样的字符。

在代码中,我们可以这样实现逐行处理:

import re def clean_text_line(line): # 匹配所有中文字符、英文字母和数字 pattern = re.compile(r'[\u4e00-\u9fa5a-zA-Z0-9]+') # findall 返回所有匹配结果的列表 matched_parts = pattern.findall(line) # 将匹配到的部分无缝拼接起来 cleaned_line = ''.join(matched_parts) return cleaned_line

这个函数会过滤掉行中所有的标点符号、空格、特殊符号(如#、$、%),只留下连续的汉字、字母和数字组合。比如,“2020年,COVID-19疫情爆发!” 处理后会变成 “2020年COVID19疫情爆发”。注意,它会把英文单词和数字粘在一起,比如“COVID-19”变成“COVID19”,这在很多文本分析场景下是可接受的,甚至是有益的,因为它减少了噪声。

在实际应用中,正则表达式可以复杂得多。例如,如果你想从文本中提取所有日期(格式如2023-01-15),可以用\d{4}-\d{2}-\d{2};提取邮箱地址,可以用更复杂的模式。关键在于精确地定义你想要的模式。我建议在编写复杂的正则表达式时,使用在线的正则表达式测试工具(如regex101.com)进行调试,这能节省大量时间。

4.2 使用OS模块自动化文件与目录管理

第二题是关于文件操作的,这几乎是每个Python脚本都会涉及的基础。osos.path模块提供了与操作系统交互的接口。题目要求查找特定类型的文件并整理路径。

search_file函数的核心是递归遍历目录。我通常使用os.walk函数,它非常方便:

import os def search_file(target_dir, extensions): file_list = [] for root, dirs, files in os.walk(target_dir): for file in files: # 获取文件扩展名并转换为小写比较 if os.path.splitext(file)[1].lower() in extensions: # 拼接完整路径 full_path = os.path.join(root, file) file_list.append(full_path) return file_list

os.walk会生成目录树中每个目录的路径、子目录列表和文件列表。os.path.splitext可以将文件名和扩展名分开。这里将扩展名转为小写再比较,是为了兼容.TXT.txt等情况,让程序更健壮。

save_file函数涉及路径创建和文件写入。这里有个关键点:目标目录可能不存在。所以,在写入文件之前,一定要检查并创建目录:

def save_file(file_paths, output_dir, output_filename='fileList.txt'): # 确保输出目录存在,如果不存在则创建 if not os.path.exists(output_dir): os.makedirs(output_dir) # makedirs可以创建多级目录 output_path = os.path.join(output_dir, output_filename) with open(output_path, 'w', encoding='utf-8') as f: for path in file_paths: f.write(path + '\n') # 每个路径占一行 print(f"文件列表已保存至: {output_path}")

使用os.makedirs并设置exist_ok=True参数(Python 3.2+)可以避免因目录已存在而报错。文件操作务必使用with open() as f的上下文管理器语法,它能确保文件被正确关闭,即使中间发生异常。这些看似微小的习惯,能极大提升代码的可靠性。

5. 让数据说话:从静态图表到动态词云

5.1 使用Matplotlib绘制专业统计图表

数据可视化是数据分析的点睛之笔。第五部分要求用Matplotlib绘制折线图、柱状图和饼图。Matplotlib虽然底层,但定制能力极强。很多新手觉得它默认的图表不好看,其实只要稍加调整,就能做出出版级的图表。

折线图常用于展示数据随时间的变化趋势。题目要求绘制长沙市疫情走势。关键步骤和技巧如下:

  1. 创建画布与子图fig, ax = plt.subplots(figsize=(15,5))。我更喜欢使用面向对象的API(ax.plot)而不是基于状态的API(plt.plot),因为它在处理多个图表时更清晰。
  2. 绘图与样式定制ax.plot(dates, confirmed_cases, linestyle='-', color='#68BFCF', marker='o', markersize=8, linewidth=2)。这里指定了线型、颜色、标记点样式。标记点能让数据点更突出。
  3. 添加数据标签:这是让图表更易懂的重要一步。可以用循环为每个点添加文本:for x, y in zip(dates, confirmed_cases): ax.text(x, y, str(y), ha='center', va='bottom', fontsize=9)hava控制文本的水平、垂直对齐方式。
  4. 美化图表元素
    • 标题与坐标轴标签ax.set_title('长沙市疫情走势', fontsize=20, pad=15)pad参数可以调整标题与图的距离。
    • 网格线ax.grid(True, linestyle='--', alpha=0.6)。设置虚线网格和透明度,让网格不那么突兀。
    • 坐标轴刻度:如果日期标签太长发生重叠,可以使用plt.xticks(rotation=45)旋转45度显示。

柱状图适合比较不同类别的数据。绘制长沙市每日确诊人数柱状图时,颜色列表['#DF927C','#A3C272',...]提供了丰富的色彩。使用ax.bar(x, height, color=colors, width=0.6, edgecolor='black')绘制,edgecolor给柱体添加边框,显得更精致。同样,在柱顶添加数据标签。

饼图用于显示各部分占整体的比例。绘制湖南省各地区确诊占比时,有几个要点:

  1. 突出显示:可以使用explode参数让某一块“炸”出来,比如explode = (0.1, 0, 0, 0, 0)让第一块分离。
  2. 标签与百分比ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90, textprops={'fontsize': 12})autopct控制百分比格式,startangle设置起始角度(90度是从顶部开始)。
  3. 图例与布局ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.0))bbox_to_anchor可以微调图例的位置,避免与饼图重叠。

最后,使用plt.tight_layout()自动调整子图参数,使图表元素不重叠,然后用fig.savefig('output.jpg', dpi=300, bbox_inches='tight')保存。dpi设置分辨率,bbox_inches='tight'可以裁掉图表周围多余的空白。

5.2 使用WordCloud生成洞察力词云

词云是一种直观展示文本关键词频率的视觉呈现方式。题目要求对疫情相关文本生成词云。步骤比图表生成稍复杂一些。

首先,需要准备文本。使用jieba库进行中文分词是标准操作:words = jieba.lcut(full_text)。分词后,我们得到一个词语列表。但直接用它生成词云效果不好,因为包含了大量无意义的“的”、“了”、“在”等停用词。所以,我们需要一个停用词列表来过滤。你可以从网上下载一个中文停用词表,或者自己构建一个。

过滤后,我们需要统计词频。Python的collections.Counter是完美工具:

from collections import Counter filtered_words = [word for word in words if word not in stopwords and len(word) > 1] # 同时过滤单字 word_freq = Counter(filtered_words).most_common(100) # 取前100个高频词

word_freq是一个类似[('疫情', 85), ('防控', 76), ...]的列表。

接下来,配置词云对象。WordCloud提供了丰富的定制选项:

from wordcloud import WordCloud import matplotlib.pyplot as plt wc = WordCloud( font_path='msyh.ttc', # 必须指定中文字体路径,否则显示乱码 width=1100, height=860, background_color='white', max_words=200, # 最多显示词数 max_font_size=150, # 最大字体大小 min_font_size=10, colormap='viridis', # 配色方案,如'plasma', 'summer' contour_width=1, contour_color='steelblue' )

font_path是关键,务必指向一个系统中存在的、支持中文的.ttf字体文件。colormap可以改变词云的整体色调,我推荐尝试'viridis','plasma','inferno'等Matplotlib内置的配色,它们比单一颜色更有层次感。

最后,用词频数据生成词云图像:wc.generate_from_frequencies(dict(word_freq))。然后使用Matplotlib显示和保存:plt.imshow(wc, interpolation='bilinear')interpolation参数设置插值方法,让图像更平滑。plt.axis('off')可以关闭坐标轴。保存为图片:wc.to_file('wordcloud.png')

在实际项目中,你可以将词云生成函数集成到Web后台中,当用户上传文本或选择分析范围后,动态生成词云图片并展示在网页上,这会让你的数据管理系统显得非常专业和强大。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 20:50:21

NVLink与PCIe深度对比:如何为AI与高性能计算选择最佳互联方案

1. 为什么AI和高性能计算需要高速互联技术 想象一下你正在指挥一支交响乐团&#xff0c;如果乐手们之间传递乐谱的速度太慢&#xff0c;整个演出就会变得杂乱无章。在AI训练和高性能计算领域&#xff0c;GPU之间的数据传输就像乐手传递乐谱一样关键。当模型参数规模突破百亿级别…

作者头像 李华
网站建设 2026/4/21 7:24:54

定制直播间坑位费,退货退款,佣金三合一智能净收益核算模板。

直播电商公司做内训时&#xff0c;发现一个非常典型的问题&#xff1a;❌ 财务还在用 Excel 手工算直播收益❌ 退货没扣干净❌ 佣金按 GMV 乱算❌ 多场直播数据对不上于是我花半天时间&#xff0c;用 Python 搭了一套「直播间坑位费 退货退款 佣金」三合一核算系统今天这篇文…

作者头像 李华
网站建设 2026/4/11 20:49:46

CD刻录实战指南:碟片选择与软件搭配的深度解析

1. CD刻录碟片选购指南 刻录CD的第一步就是选择合适的碟片。市面上常见的品牌包括铭大、铼德、三菱、万盛等&#xff0c;每种碟片都有其特点和适用场景。作为用过几十种碟片的老玩家&#xff0c;我来分享下实战经验。 先说说碟片的类型。主要分为数据碟和音乐专用碟两种。数据碟…

作者头像 李华
网站建设 2026/4/21 7:23:46

收藏!2026年程序员进化指南:AI时代如何不被淘汰,掌握这三大核心能力

马斯克预测AI将直接编写二进制代码&#xff0c;AI在代码生成、调试、文档编写等方面效率远超人类程序员。2026年&#xff0c;程序员将面临巨大变革&#xff0c;传统编码者、只会CRUD的程序员和依赖百度的程序员将被淘汰。高级程序员需具备需求梳理、智能体调度和架构质量把控能…

作者头像 李华
网站建设 2026/4/11 20:46:25

从数据采集到回放验证:ADTF 适配 ROS 的 ADAS 测试实践缎

一、简化查询 1. 先看一下查询的例子 /// /// 账户获取服务 /// /// /// public class AccountGetService(AccountTable table, IShadowBuilder builder) {private readonly SqlSource _source new(builder.DataSource);private readonly IParamQuery _accountQuery build…

作者头像 李华
网站建设 2026/4/11 20:46:00

3步掌握Autovisor:彻底改变你的智慧树学习体验

3步掌握Autovisor&#xff1a;彻底改变你的智慧树学习体验 【免费下载链接】Autovisor 2025智慧树刷课脚本 基于Python Playwright的自动化程序 [有免安装版] 项目地址: https://gitcode.com/gh_mirrors/au/Autovisor 还在为智慧树课程的繁琐操作而烦恼吗&#xff1f;每…

作者头像 李华