Python大作业实战:天气数据爬虫与可视化分析全流程
简介本资源是一份面向计算机及相关专业本科生的Python期末大作业完整实践方案聚焦网络爬虫与数据可视化核心能力训练适用于课程设计、毕业设计选题及项目实战练习。资源包含可直接运行的天气数据爬取源码、基于ECharts与HTML/CSS/JS的交互式可视化前端、配套的结课报告文档含需求分析、技术实现与结果讨论以及清晰的README说明。压缩包共514个文件主体为499个SVG图表文件用于动态天气趋势展示、3个JavaScript脚本含echarts.min.js与自定义keshihua.js、2个HTML页面登录与可视化主界面、2个CSS样式表及少量图片与SQL数据库文件整体大小22.33MB。已有383人学习下载所有代码均经本地编译调试通过评审得分98分内容获导师与助教双重审定结构规范、注释完整便于理解爬虫逻辑、数据清洗流程与前端渲染机制。 又到期末朋友圈里Python大作业的求助帖肉眼可见地多起来。翻了一圈发现大部分同学纠结的其实不是代码写不出来而是不知道怎么选一个能写、能讲、能出效果的题目。我的建议很直接如果你正在找Python大作业方向网络爬虫可视化分析这条线是最稳的组合之一尤其是爬天气数据再做可视化数据源公开稳定、技术栈覆盖广、图表直观好讲后期还能直接扩展成大作业报告的内容。这篇文章就围绕我实际做完的一个项目来讲用Python爬取多个城市的天气数据做数据清洗后用可视化工具分析温度和天气现象的规律。全文不搞花架子从选题逻辑到爬虫代码从数据处理到图表绘制再到最后报告怎么组织、答辩怎么准备我会把整个链路拆开讲清楚。适合正在准备Python大作业、想拿高分的同学参考也适合刚学完requests和pandas、想练手一个完整项目的初学者。1. 为什么把天气数据爬虫可视化作为大作业题目1.1 这个选题在大学大作业里到底香在哪里先聊一个很现实的问题Python大作业的评分逻辑多数老师看的是完整度难度讲解清晰度。完整度指你是不是真的做出了一个从数据获取到最终产出的闭环难度指你用到的技术是不是覆盖了课程核心知识点讲解清晰度则是答辩时你能不能把每个环节说明白。天气爬虫可视化恰好在这个三角上非常均衡。爬虫部分用到了requests、BeautifulSoup或者lxml这是Python网络编程的核心数据处理部分用到了pandas这是数据分析绕不开的库可视化部分用matplotlib或者pyecharts又是课程大纲里高频出现的重点。一套项目下来知识点覆盖率高报告也不会缺素材。更重要的是天气数据本身是半结构化的表格规范、字段固定对于第一次做完整项目的人来说不用处理特别离谱的脏数据。相比爬电商评论、爬租房信息天气数据的容错率高很多。我第一次带学弟做这个题目的时候他的爬虫代码大概只写了200行但数据分析部分能扩展出非常多的内容最后成绩很理想。说白了这个题目的上限很高但你不需要一开始就把上限做到先跑通再迭代即可。1.2 项目整体功能设计与模块划分在动手写代码之前我习惯先画功能模块图。不用画多复杂哪怕是纸上列几个框也能帮你梳理出我要做什么、每个模块干什么、模块之间怎么衔接。我这个项目的模块划分是这样的数据采集模块请求目标天气网站的城市历史天气页面解析HTML表格提取日期、天气现象、气温、风力风向等信息。数据存储模块把解析结果保存为CSV文件按城市月份命名方便后续分析。数据清洗模块用pandas读取CSV处理缺失值、统一格式、过滤异常温度。可视化分析模块用matplotlib和pyecharts绘制温度趋势、降雨天数、天气占比、多城市对比图。报告输出模块挑选关键图表和统计结果整理成大作业报告的素材。数据流很简单网站页面 - 爬虫解析 - CSV - pandas清洗 - 图表和统计 - 报告。我做项目的一个习惯是先把最核心的单页爬通再考虑批量。很多同学一上来就写一个for循环爬几十个页面结果页面解析逻辑有问题批量爬下来全是一堆无效数据返工成本特别高。先保证一个页面、一个城市的数据完整再扩展是效率最高的方式。1.3 数据范围与预期分析目标我自己选择的数据范围是6个城市北京、上海、广州、成都、武汉、哈尔滨近3个月的历史天气数据。选城市的时候特意考虑了纬度差异这样后面做城市对比时南北方温度差异、降雨差异会更明显图表讲起来也有内容。这个设计在答辩时是一个加分点因为老师会看到你有分析思路而不仅仅是机械地爬数据。预期分析目标也很明确一是单城市温度的月度变化趋势判断气温的整体走向二是多城市同时间段温度对比体现地域差异三是天气现象的分布统计比如晴天、多云、降雨的天数占比四是风力、空气质量等字段的简单统计。这些目标不需要多高深但能形成一个完整的分析闭环。2. 环境准备与目标站点的解析思路2.1 环境搭建与依赖包选择这个项目用到的库不多但每个都有明确分工。建议用Python 3.8以上版本越低版本容易出现依赖兼容问题。我用的依赖清单如下requests2.31.0 beautifulsoup44.12.2 lxml4.9.3 pandas2.0.3 matplotlib3.7.2 pyecharts2.0.5安装命令pip install requests beautifulsoup4 lxml pandas matplotlib pyechartspyecharts这个库特别说一下它生成的是HTML交互图表鼠标悬停可以看数值整体视觉效果比matplotlib更适合放进报告和答辩PPT。matplotlib则适合做学术感强一点的静态图比如温度折线图。两个库配合使用报告的图表类型会更丰富。2.2 目标站点分析与页面结构拆解做爬虫的第一步不是写代码而是打开目标网站看懂页面结构。我选的是天气后报这类提供历史天气查询的静态站点页面结构简单数据直接渲染在HTML表格里不需要处理JavaScript动态加载。打开一个城市的历史天气页面后在浏览器里按F12查看元素找到表格所在位置。通常结构是这样的ul classb li span2024-01-01/span span多云/span span-3℃/5℃/span span北风 3级/span /li /ul不同站点的标签会有差异关键是要找到表格每一行的规律。我的建议是先用浏览器开发者工具确认当前页面是静态渲染还是动态加载。判断方法很简单在页面空白处右键查看页面源代码如果能看到天气数据文本就是静态页面如果源代码里没有说明是AJAX动态加载需要找接口地址。为了规避反爬请求时一定要带上User-Agent模拟浏览器访问。不要让爬虫裸奔访问站点很多静态站点对无UA请求会直接返回403。另外robots协议也要遵守爬取频率尽量低建议每次请求间隔1到2秒数据仅用于学习不要大规模抓取。2.3 请求频率与反爬意识的建立这里想多说一句大作业爬虫最容易翻车的点不是代码逻辑而是请求频率。有些同学为了赶进度用for循环连续爬几百个页面间隔设为0.1秒结果爬到一半IP被封后面全挂了。我自己的做法是在爬虫里固定加time.sleep(1)或者time.sleep(random.uniform(1, 2))。加随机间隔的好处是请求模式更像真人操作也不容易触发站点的访问频率限制。答辩时可以这样讲我控制了请求频率并设置了随机间隔以减少对目标站点的访问压力。这个细节老师们普遍认可至少说明你有工程意识。3. 爬虫核心代码从单页抓取到批量落地3.1 单页抓取与HTML解析先写单页抓取函数。以某个城市2024年1月的历史天气页面为例import requests import time from bs4 import BeautifulSoup headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } def fetch_one_page(url): resp requests.get(url, headersheaders, timeout10) resp.encoding gbk # 部分历史天气站点使用gbk编码 return resp.text url https://example.com/lishi/beijing/202401.html html_text fetch_one_page(url) soup BeautifulSoup(html_text, lxml)这里有一个新手很容易踩的坑编码问题。很多国内的静态站点用的不是UTF-8而是GBK或GB2312。如果requests直接拿默认编码去解析中文全部乱码。解决办法是在解析前手动指定编码resp.encoding gbk。如果你不确定站点用的什么编码可以先用resp.apparent_encoding查看或者用chardet库检测。数据提取部分我通过选择器定位到日期和天气信息。具体选择器写法要以你实际页面的HTML结构为准这里给出一个通用逻辑def parse_weather_info(html_text): soup BeautifulSoup(html_text, lxml) items soup.select(ul.b li) # 以实际页面为准 weather_data [] for item in items: spans item.select(span) if len(spans) 4: date spans[0].text.strip() weather spans[1].text.strip() temperature spans[2].text.strip() wind spans[3].text.strip() weather_data.append({ 日期: date, 天气: weather, 气温: temperature, 风力风向: wind }) return weather_data写选择器的时候我强烈建议先在浏览器控制台里用document.querySelectorAll验证一下选中结果确认能定位到所有数据行再写进代码。很多同学喜欢凭感觉写选择器一跑发现列表是空的排查半天发现是class拼写错了一个字符。3.2 数据提取与第一轮清洗解析出来的原始数据往往带有空格、单位符号等杂质。比如气温字段是-3℃/5℃风力字段是北风 3级。如果直接存进CSV后面pandas做数值分析会非常难受。所以我在爬虫阶段就做一轮简单清洗。清洗逻辑import re def clean_temperature(temp_str): match re.findall(r-?\d, temp_str) if len(match) 2: return int(match[0]), int(match[1]) # 最低温最高温 elif len(match) 1: return int(match[0]), int(match[0]) return None, None这个函数用正则提取气温字段中的所有数字第一个数作为最低温第二个作为最高温。注意气温可能带负号所以正则里的-?一定不能漏。我见过有同学没处理负数结果哈尔滨的一月份温度全变成正数整个分析结果都错了。第一轮清洗后的字段结构为日期, 天气, 最低气温, 最高气温, 风力风向这样结构化的数据存起来后面做分析会非常顺手。3.3 多城市批量抓取与容错机制单页通了之后批量就只是加一层循环。我用一个城市列表加月份列表嵌套循环遍历所有目标URL。城市用拼音标识月份格式化为YYYYMM。import csv import random import os city_map { 北京: beijing, 上海: shanghai, 广州: guangzhou, 成都: chengdu, 武汉: wuhan, 哈尔滨: haerbin } months [202311, 202312, 202401] def fetch_city_weather(): for city, pinyin in city_map.items(): for month in months: url fhttps://example.com/lishi/{pinyin}/{month}.html try: html_text fetch_one_page(url) data_list parse_weather_info(html_text) if not data_list: print(f[{city} {month}] 无数据可能页面结构变化) continue write_to_csv(city, month, data_list) print(f[{city} {month}] 成功保存 {len(data_list)} 条数据) except Exception as e: print(f[{city} {month}] 抓取失败: {e}) continue time.sleep(random.uniform(1, 2))这里有几个工程细节值得说用try-except包裹整段抓取逻辑单个月份失败不影响整体流程。打印日志是必须的。不要用print输出大量中间数据但至少要输出每个城市、每个月份的成功/失败状态方便排查是哪个URL出了问题。time.sleep放在请求成功后而不是放在请求前避免站点返回失败后还傻傻等待。CSV保存文件的命名要带上城市和月份比如beijing_202401.csv方便后续按文件名检索。3.4 爬虫阶段常见的坑与排查思路这个部分我踩过的坑比较多整理成表格供你对照排查现象可能原因排查方向中文全部乱码页面编码不是UTF-8手动设置resp.encodinggbk或用apparent_encoding检测列表为空解析不到数据选择器写错或页面结构变化在浏览器控制台验证选择器确认数据是否静态渲染请求返回403缺少User-Agent或触发反爬添加完整请求头检查访问频率某个月份数据缺失网络波动或页面不存在单独访问该URL确认增加失败重试温度出现异常大值正则把3级风力数字也提取了检查clean_temperature的输入字段是否对应气温列最值得强调的是爬虫一旦批量运行尽量留一个调试模式只爬一个页面并打印解析结果确认无误后再全量跑。这样能避免批量爬完才发现解析逻辑全错、需要重新抓一遍的低级失误。4. 数据清洗与统计让爬下来的数据变成能用的数据4.1 pandas加载和二次清洗爬虫阶段输出的CSV已经比较规整但它只是半成品真实分析前还需要再做一次严格清洗。这一步是我认为整个项目里最体现分析能力的地方报告里值得花一页专门讲。import pandas as pd import glob df_list [] for file_path in glob.glob(data/*.csv): temp_df pd.read_csv(file_path, encodingutf-8) df_list.append(temp_df) df pd.concat(df_list, ignore_indexTrue) df[日期] pd.to_datetime(df[日期]) df df.sort_values([城市, 日期]).reset_index(dropTrue)加载完成后做三件事检查缺失值用df.isnull().sum()看每列缺失情况。如果缺失数量很少直接删除即可如果某个月整段缺失考虑重新抓取或跳过并标注。过滤异常值天气数据里偶尔会出现999℃这种明显错误数据可以用绝对阈值过滤比如最高气温介于-30到45之间超出就剔除。派生新字段比如添加月份列方便做按月聚合统计添加温差列用最高温减最低温反映昼夜温差。清洗完成后打印df.describe()看看数值列的统计概况确认数据量、均值、最值在合理范围内再进行可视化。4.2 统计指标怎么选更合理统计指标不是越多越好关键是能支撑你的分析结论。我从这个项目里提炼了几个比较有说服力的指标月平均最高温度、月平均最低温度反映整体冷暖走势。极端温度记录找到数据范围内温度最高的一天和最低的一天适合放在报告发现部分。雨天/雪天/晴天天数做天气现象统计分析。平均温差南北方城市昼夜温差差异是很好的观察点。举个例子哈尔滨1月的平均昼夜温差可以达到10度以上而广州的温差通常在5度左右。这种细节一出来报告的结论部分立刻有血有肉。5. 可视化实现从基础图表到报告级效果5.1 matplotlib绘制温度趋势图matplotlib适合画精确的、学术感的静态图。我画的第一张图是北京和哈尔滨1月每日最高温度折线对比。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False beijing_df df[(df[城市] 北京) (df[月份] 1)] haerbin_df df[(df[城市] 哈尔滨) (df[月份] 1)] fig, ax plt.subplots(figsize(12, 6)) ax.plot(beijing_df[日期], beijing_df[最高气温], markero, label北京) ax.plot(haerbin_df[日期], haerbin_df[最高气温], markero, label哈尔滨) ax.set_title(2024年1月北京与哈尔滨每日最高气温对比) ax.set_xlabel(日期) ax.set_ylabel(最高气温(℃)) ax.legend() ax.grid(True, linestyle--, alpha0.6) plt.tight_layout() plt.savefig(output/temperature_compare.png, dpi200)有一个细节新手经常忽略matplotlib默认字体不包含中文字符直接画中文标题会出现方框。解决方法是设置中文字体Windows系统通常用SimHei或Microsoft YaHeimacOS用PingFang SC或STHeiti。如果设置后仍显示方框需要检查系统里是否真的有对应字体文件。我还用matplotlib画了柱状图展示各城市月平均最高气温monthly_mean df.groupby([城市])[最高气温].mean().sort_values(ascendingFalse) fig, ax plt.subplots(figsize(10, 6)) ax.bar(monthly_mean.index, monthly_mean.values, colorskyblue, edgecolorblack) ax.set_title(各城市月平均最高气温对比) for i, v in enumerate(monthly_mean.values): ax.text(i, v 0.2, f{v:.1f}℃, hacenter) plt.tight_layout() plt.savefig(output/city_mean_temp.png, dpi200)5.2 pyecharts绘制交互式图表pyecharts的优势是生成HTML交互图表鼠标悬停可以看数值图表自带缩放、导出等功能视觉效果比matplotlib高大上很多放进大作业报告或答辩PPT里非常加分。画一个多城市最高气温走势对比图from pyecharts import options as opts from pyecharts.charts import Line line Line() line.add_xaxis(df[日期].astype(str).unique().tolist()) for city in df[城市].unique(): city_data df[df[城市] city] line.add_yaxis( city, city_data.groupby(日期)[最高气温].mean().tolist(), is_smoothTrue, is_symbol_showFalse ) line.set_global_opts( title_optsopts.TitleOpts(title多城市最高气温变化趋势), tooltip_optsopts.TooltipOpts(triggeraxis), yaxis_optsopts.AxisOpts(name气温(℃)), datazoom_opts[opts.DataZoomOpts()] ) line.render(output/multi_city_line.html)再画一个天气现象占比饼图from pyecharts.charts import Pie weather_counts df[天气].value_counts() pie Pie() pie.add( , [list(z) for z in zip(weather_counts.index, weather_counts.values)], radius[40%, 70%] ) pie.set_global_opts( title_optsopts.TitleOpts(title天气现象分布), legend_optsopts.LegendOpts(orientvertical, pos_leftleft) ) pie.set_series_opts(label_optsopts.LabelOpts(formatter{b}: {d}%)) pie.render(output/weather_pie.html)这里有一个数据预处理的前提天气现象字段需要先做归一化。因为同一个气象条件可能有多种叫法比如小雨中雨阵雨都是雨如果直接放进饼图类别太零散不如归并为雨雪多云晴阴五个大类。归并逻辑自己定义就好只要报告里说明清楚即可。5.3 图表排版与报告配图技巧做可视化部分的最后一步是把图表导出成合适格式方便嵌入报告。我总结出几个实用经验静态图保存为PNG格式dpi设为200以上保证插入Word或PPT后依然清晰。dpi低于150的图放大了会糊答辩投影时尤其明显。交互图pyecharts生成的HTML在报告中截取关键画面作为静态图插入同时在答辩现场演示HTML文件展示图表可交互性。每张图都要有明确的标题、x轴标签、y轴标签、图例。不要让老师去猜这张图在讲什么。图的大小要控制好不要宽高失衡。折线图适合长方形尺寸比如12x6饼图适合正方形比如8x8。图表数量控制在6到8张为宜。太少显得分析不充分太多则显得没有重点。每张图表在报告里都要配一段结果说明讲清楚这张图揭示了什么。6. 大作业报告的写作组织与答辩准备6.1 报告结构一张让老师满意的目录很多同学写报告是先写代码后拼报告导致报告像代码文档而大作业报告要求的其实是项目完整记录。我建议的报告结构是这样的摘要用200字概括项目目标、方法、主要结论。关键词列3到5个如Python、网络爬虫、数据分析、可视化。需求分析为什么要做这个项目解决什么问题目标用户是谁。总体设计模块划分、数据流、技术选型及理由。详细实现爬虫模块、数据处理模块、可视化模块的代码与运行截图。结果与分析展示关键图表并逐图解释数据背后的含义。总结与展望做完了什么遇到了什么问题后续可以怎么优化。模板式的四段论每段对应答辩时可能被问到的一个环节。最重要的不是代码量而是逻辑的自洽性你能解释清楚每一步为什么这么做。6.2 报告中代码呈现的常见问题报告里贴代码是必要的但别把全部代码都贴进去。我见过最糟的报告是全文复制了300行代码没有注释没有分段说明。老师看这种报告会非常痛苦因为他根本找不到重点。正确做法是核心功能贴关键代码片段每段代码前用一小段文字说明这段代码实现了什么、为什么这么写。比如爬虫解析那段可以这样配文本段代码使用BeautifulSoup解析HTML页面定位到class为b的列表遍历每一行提取日期、天气和温度字段。选择器写法经过浏览器控制台验证确保数据定位准确。这样的报告呈现既展示了你的代码能力又展示了你的逻辑思维。6.3 答辩常见问题与应答思路答辩是很多同学的紧张来源但其实大作业答辩的问题非常套路化提前准备好就能稳住。我把自己经历过的和帮学弟模拟过的问题整理成表格提问方向参考回答思路为什么选这个题目天气数据公开稳定爬虫可视化覆盖课程核心知识点分析结果直观有说服力爬虫遇到过反爬吗怎么解决的添加User-Agent模拟浏览器控制请求频率设置随机间隔如果遇到403就增加重试机制数据可信吗怎么验证抽样与气象平台新闻对比检查极端值是否合理比如北京1月最低温不会低于-20度为什么用pyecharts而不用matplotlibpyecharts支持交互式展示适合演示matplotlib适合学术静态图两者互补配合项目有什么可以改进的地方可以接入实时天气API实现动态更新可以增加预测模型可以扩大城市和年份范围有一个重要的答辩原则不会的问题不要硬编坦诚说这部分我确实还没深入了解但我的理解是……反而比强行编造更容易让老师接受。7. 项目复盘那些代码之外的收获与建议这个项目跑通之后我更深刻地意识到大作业真正锻炼的其实不是会写几个库而是把一件事完整做完的能力。从选定题目到最终产出图表和报告整个链路里有太多细节需要照顾编码问题、页面结构变化、字段清洗、字体显示、图表配色、报告排版……任何一个环节出问题都会影响最终效果。如果你是自己独立完成这个项目有几个细节可以再优化爬虫部分增加失败重试机制用requests的适配器配置重试次数避免网络抖动导致数据缺漏。数据存储考虑SQLite用表结构管理城市和日期的关系比CSV更适合数据量增加后的查询。可视化部分在pyecharts的基础上可以尝试用plotly交互能力更强图表风格也更现代。报告最后附上核心代码的关键片段不要超过10页的代码附录突出主要逻辑即可。最后分享一个我自己的小习惯项目做完了不要急着删代码保留好所有中间文件和数据副本。答辩前一周重新跑一遍完整流程确认代码在当前环境下仍然能运行。很多同学答辩当天才发现环境依赖变了、代码跑不起来了这种低级失误最影响分数。提前跑通稳住心态大作业自然水到渠成。本文还有配套的精品资源点击获取