简介本资源是一套完整的Python数据工程实践项目面向计算机、数学与电子信息等专业的本科生及初学者聚焦疫情数据采集、社交媒体舆情挖掘与多维度数据分析全流程。项目涵盖疫情实时爬虫、微博关键词定向抓取含MySQL数据库存储、结构化数据清洗与特征工程、Matplotlib/Seaborn可视化图表生成以及基于词典法的情感倾向分析模块可直接用于课程设计、期末大作业或毕业设计参考。压缩包共15个文件包含7个核心Python脚本覆盖爬虫、ETL、NLP分析与绘图、3个CSV数据集含标注的疫情训练样本与情感词库、2个文本词典、1个JSON微博原始数据样例、1张分析结果PNG图及1份Markdown项目说明文档整体大小为23.87MB。已有728人学习下载提供从数据获取到价值呈现的端到端代码实现目录结构清晰模块职责分明便于理解流程逻辑、调试扩展功能或迁移至其他主题分析场景。1. 项目概述一个数据驱动的疫情社会感知系统看到这个项目标题我第一反应是这是一个典型的、从数据采集到价值洞察的端到端数据工程与数据分析实战项目。它绝不仅仅是一个简单的“爬虫脚本”而是一个融合了网络数据采集、结构化存储、数据清洗、可视化呈现以及情感挖掘的微型系统。对于想从“会写Python脚本”进阶到“能解决实际业务问题”的数据爱好者或初级数据分析师来说这是一个绝佳的练手项目。项目的核心逻辑非常清晰从公开的疫情数据网站和社交媒体微博抓取原始信息存入数据库进行规整然后通过数据预处理将其转化为可供分析的“干净”数据最后通过可视化图表直观展示疫情态势并利用情感分析技术洞察公众情绪变化。这几乎复刻了一个数据团队在面对一个突发公共事件时进行数据监控与舆情分析的标准工作流。通过亲手实现它你能系统性掌握数据获取、处理、分析和呈现的全链条技能理解每个环节的技术选型考量和潜在陷阱。2. 核心模块深度拆解与技术选型这个项目可以清晰地拆解为五个核心模块每个模块都涉及不同的技术栈和设计决策。下面我们来逐一剖析。2.1 疫情数据爬虫稳定、合规与反爬应对疫情数据通常来源于各级卫健委官网、权威数据平台如丁香园、腾讯健康等。这部分爬虫的设计核心在于稳定性和合规性。技术选型与原理请求库首选requests。它简单易用足以应对大多数静态页面。对于动态渲染的页面数据通过JavaScript异步加载则需要Selenium或Playwright来模拟浏览器行为。考虑到疫情数据页面结构通常不复杂requests 定期抓取是性价比最高的方案。解析库BeautifulSoup或lxml。BeautifulSoup的API更友好适合HTML结构不规则或快速原型开发lxml的解析速度和效率更高适合处理大量页面。本项目数据量不会特别巨大两者皆可但更推荐lxml配合XPath定位元素更精准。关键设计考量请求头Headers模拟必须设置完整的User-Agent、Referer等模拟真实浏览器访问这是绕过基础反爬的第一步。请求频率控制务必在代码中加入time.sleep(random.uniform(1, 3))这样的随机延时避免高频请求对目标服务器造成压力这也是基本的网络礼仪和规避IP封锁的手段。数据源稳定性优先选择提供结构化数据接口如果有的话或页面结构稳定的官网。避免抓取过于复杂或频繁改版的商业站点。错误处理与重试网络请求充满不确定性。必须用try...except包裹请求代码并对连接超时、状态码非200等情况设计重试机制如tenacity库和日志记录。实操心得我曾抓取某地方卫健委网站其表格数据藏在多层div下直接用BeautifulSoup找table标签会失败。后来通过浏览器开发者工具的“检查”功能复制了数据的XPath路径用lxml的xpath方法一举搞定。记住“右键检查”是你最好的朋友。2.2 微博关键词爬虫动态内容与登录态管理微博爬虫是项目的难点之一因为微博页面是典型的动态渲染且对未登录用户有严格的访问限制。技术选型与原理核心工具Selenium或Playwright。它们能驱动真实浏览器执行JavaScript完美解决动态加载问题。Playwright是后起之秀在速度和API设计上更优但Selenium生态更成熟。登录态维持这是关键。有两种思路模拟登录用Selenium自动填充账号密码处理验证码复杂易失效。Cookie复用手动登录微博后通过浏览器开发者工具导出Cookie字符串在代码中直接加载。这是更稳定、更推荐的方法。但需要注意Cookie有有效期需要定期更新。数据定位微博的博文、发布时间、转发评论赞等数据其HTML标签和类名经常变动。不能写死选择器。应该使用更稳定的定位方式如通过“包含文本”的属性选择器或者利用页面结构中的不变元素进行相对定位。翻页与滚动微博采用“瀑布流”无限加载。需要模拟浏览器滚动到底部触发新内容加载。Selenium可以使用driver.execute_script(“window.scrollTo(0, document.body.scrollHeight)”)来实现。数据库设计 抓取的微博数据需要存入数据库。表结构设计至关重要。一个基本的weibo_data表可能包含以下字段CREATE TABLE weibo_data ( id INT PRIMARY KEY AUTO_INCREMENT, keyword VARCHAR(255), -- 搜索关键词 content TEXT, -- 博文内容 publish_time DATETIME, -- 发布时间 user_name VARCHAR(255), -- 发布者昵称 repost_count INT, -- 转发数 comment_count INT, -- 评论数 like_count INT, -- 点赞数 crawl_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 爬取时间 );这里将keyword作为字段便于后续按不同关键词进行筛选和分析。踩坑记录微博对自动化工具检测很强。直接使用默认的Selenium驱动很容易被识别。解决方案是添加excludeSwitches: [‘enable-automation’]选项或者使用undetected-chromedriver这类专门绕过检测的驱动。此外一定要设置合理的爬取间隔避免账号异常。2.3 数据预处理从“脏数据”到“干净数据”爬取到的原始数据Raw Data往往是不能直接用于分析的“脏数据”。数据预处理Data Preprocessing的目的就是将其转化为高质量、一致化的“干净数据”。典型问题与处理流程缺失值处理疫情数据中某天的“新增治愈”字段可能为空。处理方式包括删除该条记录若缺失很少、用均值/中位数填充、或用前后数据插值。对于微博数据用户昵称缺失可能直接填充为“未知用户”。异常值处理某条疫情数据中“新增确诊”为100000这显然是异常。可以通过箱线图Boxplot或标准差如3σ原则识别异常值并根据业务逻辑决定是修正还是删除。格式标准化日期/时间原始数据可能是“2023-01-01”、“2023/01/01”、“1月1日”等多种格式。必须统一转换为datetime类型。文本清洗微博内容包含大量“用户”、“#话题#”、表情符号、URL链接。需要使用正则表达式re库将其去除只保留核心文本内容为后续情感分析做准备。数字处理将字符串类型的数字如“1234”转换为整数或浮点数。数据集成疫情数据和微博数据可能是两个独立的表或数据源。如果需要关联分析例如分析某日疫情数字与微博情绪的关系就需要通过“日期”这个关键字段进行连接JOIN。技术实现Pandas是完成这一切的瑞士军刀。DataFrame结构提供了强大的数据操作能力。import pandas as pd # 读取数据 df pd.read_sql(‘SELECT * FROM pandemic_data‘, conengine) # 处理缺失值用前一天的数值填充 df[‘new_cases‘].fillna(method‘ffill‘, inplaceTrue) # 转换日期格式 df[‘date‘] pd.to_datetime(df[‘date‘], format‘%Y-%m-%d‘) # 文本清洗示例去除微博内容中的和话题 import re def clean_weibo_text(text): text re.sub(r‘\S‘, ‘‘, text) # 去除用户 text re.sub(r‘#\S#‘, ‘‘, text) # 去除#话题# text re.sub(r‘http\S‘, ‘‘, text) # 去除URL return text.strip() df_weibo[‘cleaned_content‘] df_weibo[‘content‘].apply(clean_weibo_text)2.4 数据可视化让数据“说话”可视化是将预处理后的数据转化为直观洞见的关键一步。目标是用最合适的图表讲述数据背后的故事。可视化库选型Matplotlib基础且强大高度可定制但API稍显繁琐。适合绘制出版级质量的复杂静态图表。Seaborn基于Matplotlib提供了更高级的API和美观的默认样式特别擅长统计图表如分布图、热力图、分类散点图。Pyecharts或Plotly生成交互式图表可以嵌入网页。Pyecharts基于ECharts中文文档友好Plotly功能极其强大社区活跃。对于需要展示动态趋势或细节查询的场景交互式图表是更好的选择。可视化场景设计疫情趋势总览使用折线图Line Chart展示全国或重点区域每日“累计确诊”、“新增确诊”、“累计治愈”的变化趋势。多条折线在同一坐标系下可以清晰对比。疫情地理分布使用分级统计地图Choropleth Map展示各省市的确诊病例数。Pyecharts的Map组件可以轻松实现。微博舆情时间线将微博每日的发布数量、平均情感分数绘制成折线图并与疫情趋势图进行对照观察舆论热度与疫情发展的关联。关键词词云对清洗后的微博内容进行分词生成词云Word Cloud直观展示公众讨论的焦点。代码示例使用Seaborn绘制疫情趋势import seaborn as sns import matplotlib.pyplot as plt sns.set_style(“whitegrid”) # 设置样式 plt.figure(figsize(14, 7)) # 绘制新增确诊和新增治愈两条折线 sns.lineplot(datadf, x‘date‘, y‘new_cases‘, label‘新增确诊‘, color‘red‘, marker‘o‘) sns.lineplot(datadf, x‘date‘, y‘new_cures‘, label‘新增治愈‘, color‘green‘, marker‘s‘) plt.title(‘每日新增确诊与治愈趋势对比‘, fontsize16) plt.xlabel(‘日期‘) plt.ylabel(‘人数‘) plt.legend() plt.xticks(rotation45) # 旋转日期标签避免重叠 plt.tight_layout() plt.show()2.5 数据情感分析洞察公众情绪脉搏情感分析Sentiment Analysis旨在判断一段文本所表达的情感倾向正面、负面、中性。在这个项目中它用于量化微博舆论对疫情的情绪反应。方法选择基于词典的方法如使用SnowNLP针对中文优化。其原理是内置一个情感词典计算文本中正面词汇和负面词汇的权重总和。优点是速度快、无需训练缺点是精度一般无法理解上下文和反讽。from snownlp import SnowNLP text “今天疫情好转了真开心“ s SnowNLP(text) print(s.sentiments) # 输出一个0-1之间的值越接近1越正面基于机器学习/深度学习的方法使用如sklearn训练一个分类模型或使用预训练的深度学习模型如BERT。这需要大量的标注数据每条微博标好正面/负面精度高但实现复杂、计算成本高。项目中的实践建议 对于入门级项目推荐使用SnowNLP或百度AI开放平台、腾讯云NLP等提供的现成情感分析API。它们提供了不错的基线效果。可以将每条微博的情感得分0-1计算出来作为新的字段存入数据库然后按天计算平均情感得分观察公众情绪的走势。结果解读 情感得分本身只是一个数字。更重要的是将其与事件结合分析。例如你可能发现当“新增确诊”大幅上升时微博的平均情感得分会显著下降情绪变负面而当官方发布“疫苗研发进展”利好消息时情感得分可能上升。这种关联性分析才是情感分析的价值所在。注意事项情感分析不是万能的。对于“真是‘好’消息啊”这样的反讽句基于词典的方法很可能误判为正面。因此在呈现结果时务必说明其局限性并建议结合人工抽样复核。3. 项目架构与工程化实践一个可运行、易维护的项目离不开好的代码结构和工程化管理。我们不应该把所有代码都堆在一个.py文件里。3.1 推荐的项目目录结构pandemic-sentiment-analysis/ ├── config/ # 配置文件 │ └── settings.py # 数据库连接、API密钥、关键词列表等配置 ├── src/ # 源代码 │ ├── crawler/ # 爬虫模块 │ │ ├── pandemic_crawler.py # 疫情数据爬虫 │ │ └── weibo_crawler.py # 微博爬虫 │ ├── database/ # 数据库模块 │ │ ├── models.py # SQLAlchemy ORM 模型定义 │ │ └── db_handler.py # 数据库连接与操作封装 │ ├── processor/ # 数据处理模块 │ │ ├── data_cleaner.py # 数据清洗函数 │ │ └── sentiment_analyzer.py # 情感分析函数 │ └── visualization/ # 可视化模块 │ └── plot_generator.py # 图表生成函数 ├── data/ # 数据目录 │ ├── raw/ # 原始数据可选本地备份 │ └── processed/ # 处理后的数据文件 ├── logs/ # 日志目录 │ └── app.log # 运行日志 ├── requirements.txt # 项目依赖包列表 ├── main.py # 项目主入口调度各个模块 └── README.md # 项目详细说明文档3.2 使用配置文件管理敏感信息绝对不要将数据库密码、API密钥等硬编码在代码中使用配置文件或环境变量。# config/settings.py DATABASE_CONFIG { ‘host‘: ‘localhost‘, ‘port‘: 3306, ‘user‘: ‘your_username‘, ‘password‘: ‘your_password‘, # 实际中应从环境变量读取 ‘database‘: ‘pandemic_db‘ } KEYWORDS [‘疫情‘, ‘新冠‘, ‘健康码‘] # 要爬取的微博关键词在主程序中通过from config import settings引入。3.3 日志记录至关重要良好的日志能帮你快速定位线上问题。使用Python内置的logging模块。import logging logging.basicConfig( levellogging.INFO, format‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘, handlers[ logging.FileHandler(‘./logs/app.log‘), logging.StreamHandler() # 同时在控制台输出 ] ) logger logging.getLogger(__name__) logger.info(‘开始爬取疫情数据...‘)4. 从零到一的完整实现流程假设我们使用MySQL数据库下面勾勒一个从环境搭建到运行的主流程。4.1 环境准备与依赖安装安装Python确保安装Python 3.7及以上版本。创建虚拟环境推荐python -m venv venv然后激活它。安装依赖将以下内容保存为requirements.txt然后运行pip install -r requirements.txt。requests2.28.0 beautifulsoup44.11.0 lxml4.9.0 selenium4.0.0 pandas1.5.0 sqlalchemy1.4.0 pymysql1.0.0 matplotlib3.5.0 seaborn0.12.0 snownlp0.12.0 jieba0.42.0 # 用于中文分词 schedule1.0.0 # 用于定时任务数据库准备安装MySQL创建一个名为pandemic_db的数据库。4.2 核心代码编写步骤第一步建立数据库连接与表模型使用SQLAlchemy ORM来定义数据表这样操作数据库更Pythonic。# src/database/models.py from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, Float from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from config import settings engine create_engine( f“mysqlpymysql://{settings.DATABASE_CONFIG[‘user‘]}:{settings.DATABASE_CONFIG[‘password‘]}” f“{settings.DATABASE_CONFIG[‘host‘]}:{settings.DATABASE_CONFIG[‘port‘]}/” f“{settings.DATABASE_CONFIG[‘database‘]}?charsetutf8mb4“ ) Base declarative_base() SessionLocal sessionmaker(bindengine) class PandemicData(Base): __tablename__ ‘pandemic_data‘ id Column(Integer, primary_keyTrue) date Column(DateTime, nullableFalse, indexTrue) # 加索引加快查询 region Column(String(100)) new_cases Column(Integer) new_deaths Column(Integer) new_cures Column(Integer) crawl_time Column(DateTime) class WeiboData(Base): __tablename__ ‘weibo_data‘ # ... 字段定义如前文所述 sentiment Column(Float) # 新增字段存储情感得分 Base.metadata.create_all(engine) # 创建表第二步编写疫情数据爬虫以抓取一个模拟的静态数据页面为例。# src/crawler/pandemic_crawler.py import requests from lxml import etree import pandas as pd from datetime import datetime from database.models import SessionLocal, PandemicData import time import logging logger logging.getLogger(__name__) def crawl_pandemic_data(): url “https://example.com/pandemic-data“ # 替换为真实URL headers {‘User-Agent‘: ‘Mozilla/5.0...‘} try: resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() # 检查请求是否成功 html etree.HTML(resp.text) # 假设数据在一个id为‘data-table‘的表格里 rows html.xpath(‘//table[id“data-table“]/tbody/tr‘) data_list [] for row in rows: cols row.xpath(‘./td/text()‘) # 解析每一列数据这里需要根据实际网页结构调整 record { ‘date‘: datetime.strptime(cols[0], ‘%Y-%m-%d‘), ‘region‘: cols[1], ‘new_cases‘: int(cols[2]), ‘new_deaths‘: int(cols[3]), ‘new_cures‘: int(cols[4]) } data_list.append(record) # 存入数据库 session SessionLocal() for record in data_list: # 避免重复插入根据日期和地区检查 exists session.query(PandemicData).filter_by(daterecord[‘date‘], regionrecord[‘region‘]).first() if not exists: db_record PandemicData(**record, crawl_timedatetime.now()) session.add(db_record) session.commit() session.close() logger.info(f“成功爬取并存储 {len(data_list)} 条疫情数据。“) except Exception as e: logger.error(f“爬取疫情数据失败: {e}“) finally: time.sleep(2) # 礼貌性延时第三步编写微博爬虫使用Cookie登录# src/crawler/weibo_crawler.py from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time from database.models import SessionLocal, WeiboData from config import settings import logging logger logging.getLogger(__name__) def crawl_weibo_by_keyword(keyword): options webdriver.ChromeOptions() options.add_argument(‘--headless‘) # 无头模式不显示浏览器窗口 options.add_experimental_option(“excludeSwitches”, [“enable-automation”]) driver webdriver.Chrome(optionsoptions) # 加载Cookie driver.get(“https://weibo.com“) with open(‘weibo_cookies.txt‘, ‘r‘) as f: # 事先手动登录后导出的cookie文件 cookies eval(f.read()) for cookie in cookies: driver.add_cookie(cookie) driver.refresh() # 搜索关键词 search_url f“https://s.weibo.com/weibo?q{keyword}“ driver.get(search_url) time.sleep(3) weibo_list [] for i in range(3): # 模拟滚动3次抓取一定数量 # 定位微博卡片这里的选择器需要根据微博实际页面更新 cards driver.find_elements(By.CSS_SELECTOR, ‘div.card‘) for card in cards: try: content card.find_element(By.CSS_SELECTOR, ‘p.txt‘).text # ... 类似地提取其他信息时间、用户、转发数等 weibo_data { ‘keyword‘: keyword, ‘content‘: content, # ... 其他字段 } weibo_list.append(weibo_data) except Exception as e: continue # 滚动到底部 driver.execute_script(“window.scrollTo(0, document.body.scrollHeight);”) time.sleep(2) driver.quit() # 存入数据库 session SessionLocal() for wb in weibo_list: db_record WeiboData(**wb, crawl_timedatetime.now()) session.add(db_record) session.commit() session.close() logger.info(f“关键词 ‘{keyword}‘ 爬取完成获得 {len(weibo_list)} 条微博。“)第四步主程序调度# main.py import schedule import time from src.crawler import pandemic_crawler, weibo_crawler from src.processor import data_cleaner, sentiment_analyzer from src.visualization import plot_generator from config import settings import logging logging.basicConfig(levellogging.INFO) def daily_job(): logging.info(“开始执行每日数据任务...“) # 1. 爬取数据 pandemic_crawler.crawl_pandemic_data() for kw in settings.KEYWORDS: weibo_crawler.crawl_weibo_by_keyword(kw) # 2. 数据预处理与情感分析可以稍后执行或独立调度 data_cleaner.clean_and_process() sentiment_analyzer.batch_analyze_sentiment() logging.info(“每日数据任务执行完毕。“) def weekly_visualization(): logging.info(“生成每周可视化报告...“) plot_generator.generate_trend_chart() plot_generator.generate_sentiment_timeline() logging.info(“可视化报告生成完毕。“) if __name__ ‘__main__‘: # 立即执行一次 daily_job() weekly_visualization() # 设置定时任务每天上午10点执行 schedule.every().day.at(“10:00”).do(daily_job) # 每周一上午11点执行 schedule.every().monday.at(“11:00”).do(weekly_visualization) while True: schedule.run_pending() time.sleep(60)5. 避坑指南与进阶思考在实际运行中你一定会遇到各种问题。这里分享一些我踩过的坑和解决方案。5.1 常见问题排查表问题现象可能原因排查步骤与解决方案爬虫返回空数据或403错误1. 请求头未正确设置。2. IP被目标网站暂时封锁。3. 页面动态加载需用Selenium。1. 检查并完善Headers特别是User-Agent和Referer。2. 增加请求间隔使用代理IP池需谨慎注意合规。3. 打开浏览器开发者工具查看Network中XHR/Fetch请求尝试直接抓取接口数据或改用Selenium。数据库连接失败1. 连接参数主机、端口、密码错误。2. 数据库服务未启动。3. 客户端IP未被授权访问。1. 仔细核对settings.py中的配置。2. 在命令行检查MySQL服务状态并启动。3. 登录MySQL执行GRANT ALL ON database.* TO ‘user‘‘client_ip‘;授权。情感分析结果不准确1. 文本未充分清洗残留特殊符号、话题。2. SnowNLP词典对特定领域如疫情词汇覆盖不足。3. 遇到反讽、复杂句式。1. 加强文本预处理去除所有无关符号和停用词。2. 考虑使用领域情感词典微调或尝试调用大厂云API如百度NLP。3. 理解其局限性结果仅作趋势参考关键结论需人工复核。可视化图表中文乱码Matplotlib默认字体不包含中文。在绘图代码前添加以下配置plt.rcParams[‘font.sans-serif‘] [‘SimHei‘, ‘DejaVu Sans‘]plt.rcParams[‘axes.unicode_minus‘] False定时任务不执行1. 主程序脚本在睡眠时被终止。2.schedule在无GUI环境的服务器上可能有问题。1. 使用系统的定时任务如Linux的crontabWindows的任务计划程序来调用你的Python脚本更稳定可靠。2. 确保脚本有执行权限且Python路径正确。5.2 项目进阶方向完成基础版本后你可以从以下几个方向深化项目提升其价值和复杂度数据源扩展与融合除了疫情数字和微博还可以接入百度搜索指数、新闻客户端报道、股票市场相关板块波动等多元数据进行更全面的关联分析。实时数据流处理将定时爬虫升级为近实时监控。可以考虑使用ScrapyKafkaSpark Streaming的架构实现数据的实时采集、处理与可视化如Dash/Streamlit Web应用。情感分析模型优化放弃简单的词典方法尝试使用预训练的中文BERT模型如bert-base-chinese在自己的微博数据集上进行微调Fine-tuning构建一个更精准的疫情舆情情感分类模型。自动化报告生成将生成的可视化图表、关键指标如每日情绪指数、热门话题自动整合到一份PDF或HTML报告中并通过邮件定时发送。部署与运维将整个项目容器化Docker并部署到云服务器上。使用Supervisor或systemd来管理进程确保7x24小时稳定运行。这个项目就像一个数据技能的“练兵场”从最初的脚本编写到模块化设计再到调度部署每一步都对应着真实工作场景中的需求。当你完整地走通一遍再回头看“爬虫”、“数据分析”这些词你的理解将不再是几个孤立的函数而是一个环环相扣、能够创造价值的系统工程。本文还有配套的精品资源点击获取
