Python爬虫+数据可视化:天气轮播图完整项目实战

发布时间:2026/8/31 4:12:52
Python爬虫+数据可视化:天气轮播图完整项目实战 最近不少同学都在找 Python 期末大作业的完整案例。如果项目既要体现爬虫又要把数据可视化做出来还要在答辩或演示时有点亮点那“天气数据爬取 数据可视化 天气轮播图”这一套组合就非常合适。它把 Python 爬虫、数据处理和图表展示都串起来了而且天气数据来源直观、演示效果好不用像电商爬虫一样担心账号状态和复杂反爬。这次我们就完整拆解这个项目从 Python 环境准备、requests 爬虫抓取天气数据到 pandas 清洗、pyecharts 绘制天气轮播图最后看如何用定时任务做批量抓取以及常见问题的排查思路。这个项目的核心思路不复杂用 Python 请求天气数据页面或公开数据接口拿到 JSON 或 HTML 后解析出城市、日期、温度、湿度、风力、天气状况等字段存到 CSV 或数据库里再用 pyecharts 的 Timeline 组件做“天气轮播图”把多天的天气变化按时间播放出来。相比单纯写一个静态表格轮播图在答辩现场更直观也能体现出对数据可视化的理解。下面直接进入正题。1. 项目核心能力速览先把这个项目能做什么、用什么工具、跑起来需要什么条件列清楚。下面的信息既适合期末大作业选题参考也适合想入门爬虫加可视化的读者做练手。能力项说明项目类型Python 爬虫 数据清洗 数据可视化核心技术栈requests、BeautifulSoup、pandas、pyecharts、matplotlib主要功能爬取天气数据、解析关键字段、存储 CSV、绘制天气轮播图数据类型城市、日期、气温、湿度、风力、天气状况等展示形式pyecharts Timeline 时间轮播图 / HTML 页面操作难度中等适合已掌握 Python 基础语法的学习者运行平台Windows / macOS / Linux 均可启动方式命令行执行脚本或 PyCharm / VS Code 直接运行是否支持批量任务支持可循环抓取多城市、多天数据是否支持接口 API爬虫阶段没有固定 API可视化结果可接入 Web 服务额外依赖需要安装 requests、beautifulsoup4、pandas、pyecharts适用场景课程设计、期末大作业、爬虫入门实践、可视化 Demo从材料看这个项目的核心价值在于“完整链路”不是单纯爬虫也不是单纯画图而是把数据获取、清洗、存储、展示串成一条线。答辩时你可以从链路每个环节讲起内容量非常充足。2. 适用场景与使用边界这个项目最适合的人群是正在做 Python 课程设计或期末大作业的学生想用真实数据做一个可视化 Demo 的初学者以及想快速熟悉 requests 加 pyecharts 完整流程的开发者。能用它解决的问题很具体快速演示 Python 爬虫基本流程请求、解析、提取字段。用 pandas 完成简单的数据清洗与转换。用 pyecharts 生成带时间轮播效果的 HTML 图表展示多天或多城市的天气变化。不适合的场景也要说清楚。如果你要爬取的是商业化天气平台要注意目标网站的服务条款和 robots.txt不能高频率请求不能用于商业分发。如果数据源要求登录或需要 API Key需要先确认是否有合法访问权限。这里必须强调合规边界。爬虫抓取公开数据用于学习和课程演示一般问题不大但要注意三点控制请求频率做好延时不要影响目标网站正常服务。不爬取需要登录、需要授权或涉及个人信息的内容。抓下来的数据如果用于论文、开源项目或商用场景要确认数据源的使用条款。另外天气数据本身也会存在滞后性。实际演示时应以运行时刻抓取到的数据为准不要声称数据来自某个官方平台除非你真的使用了对应平台的授权接口。3. 环境准备与前置条件这个项目对硬件没有特殊要求普通笔记本电脑就能跑。真正需要提前装好的是 Python 运行环境和第三方库。3.1 安装 Python优先使用 Python 3.8 及以上版本。Windows 系统建议在官网下载安装包时勾选“Add Python to PATH”这样命令行能直接运行 python。如果是 macOS 或 Linux一般自带 Python 3但版本可能偏旧建议用包管理器或 pyenv 装一个新版本。安装完成后在命令行执行python --version能看到版本号就说明环境变量配置正常。如果提示“python 不是内部或外部命令”通常是安装时没有勾选 PATH或者需要重启终端。3.2 安装第三方库推荐使用 pip 安装pip install requests beautifulsoup4 pandas pyecharts lxml如果网络下载较慢可以换用国内镜像源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests beautifulsoup4 pandas pyecharts lxml这里说明一下各个库的作用requests发送 HTTP 请求获取网页或接口数据。beautifulsoup4解析 HTML提取天气字段。lxmlBeautifulSoup 的解析器解析速度更快。pandas数据清洗、去重、保存 CSV。pyecharts生成交互式 HTML 图表支持 Timeline 轮播。3.3 开发工具PyCharm 或 VS Code 都可以。PyCharm 还需要在 Settings 里配置好 Project Interpreter避免开了新环境后找不到库。VS Code 则需要先选择 Python 解释器再安装 Python 插件。建议先把项目目录建好推荐结构如下weather_project/ ├── crawler.py # 爬虫模块 ├── visualize.py # 可视化模块 ├── requirements.txt # 依赖清单 ├── data/ │ └── weather.csv # 抓取结果 └── output/ └── weather_timeline.html # 轮播图输出划分模块的好处是后续单独运行爬虫或单独生成图表时不用重复执行整段逻辑。4. 爬虫模块设计从请求到解析爬虫模块是这个项目的入口。它的任务是从目标数据源获取天气页面或接口数据再解析出需要展示的字段。4.1 请求头与请求体很多网站会对没有 User-Agent 的请求直接拒绝。为了尽量模拟浏览器访问需要配置请求头。下面是一个通用请求模板实际 URL 需要替换成你在项目中经确认可用、并且允许访问的天气数据源import requests import time HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36, Accept: text/html,application/json,application/xhtmlxml,*/*, Accept-Language: zh-CN,zh;q0.9, } def fetch_weather_data(city: str) - str: 根据城市名称请求天气数据返回响应文本。 # 注意这里的 url 只是结构示例请替换成项目里确认可用的数据源。 url fhttps://example-weather-source.example.com/weather?city{city} resp requests.get(url, headersHEADERS, timeout10) resp.raise_for_status() resp.encoding resp.apparent_encoding return resp.text这里有几个容易踩的细节timeout 不能省否则目标站点没有响应时脚本会卡住。resp.encoding 最好根据页面或接口实际编码设置。中文页面常见 utf-8也有部分站点是 gbk直接读取可能出现乱码。如果返回的是 JSON 数据可以直接用resp.json()不需要 BeautifulSoup 解析。4.2 HTML 解析如果天气数据是嵌在 HTML 里的就用 BeautifulSoup 提取字段。下面是一个结构示例选择器要按真实页面的 class 或 id 调整from bs4 import BeautifulSoup def parse_weather_html(html: str, city: str) - dict: soup BeautifulSoup(html, lxml) # 这里的 .class 名称只是示例真实项目以页面源码为准 temperature soup.select_one(.current-temp).get_text(stripTrue) weather_desc soup.select_one(.weather-desc).get_text(stripTrue) humidity soup.select_one(.humidity).get_text(stripTrue) wind soup.select_one(.wind-level).get_text(stripTrue) return { city: city, temperature: temperature, weather: weather_desc, humidity: humidity, wind: wind, update_time: time.strftime(%Y-%m-%d %H:%M:%S), }这段代码的逻辑重点不是选择器本身而是“解析流程”先定位到包含天气信息的节点。用get_text(stripTrue)去掉空白字符。把字段放进字典方便后续转 DataFrame。如果页面结构发生了变化最常见的结果是select_one返回 None这时候不要直接.get_text()否则会报 AttributeError。可以先判空。4.3 多城市批量抓取批量抓取是期末项目里很容易加分的点。把城市列表循环处理每次请求之间加一个time.sleep控制频率CITIES [北京, 上海, 广州, 深圳] def batch_fetch(cities: list[str]) - list[dict]: results [] for city in cities: try: html fetch_weather_data(city) data parse_weather_html(html, city) results.append(data) print(f[OK] {city}: {data[temperature]}℃ {data[weather]}) except Exception as e: print(f[FAIL] {city}: {e}) time.sleep(2) return results批量抓取时不要用一个请求打满整个站点设置 1 到 3 秒的延时即可。也可以用random.uniform(1, 2)生成随机延时避免节奏太规律。5. 数据清洗与存储爬虫拿到原始数据后往往不能直接画图。比如温度字段可能是“25℃体感27℃”湿度可能是“65%RH”这些字符串需要清洗成数值或统一格式。5.1 数据清洗用 pandas 做清洗比较方便import pandas as pd def clean_weather_data(items: list[dict]) - pd.DataFrame: df pd.DataFrame(items) # 把温度中的“℃”去掉转成数值型失败时置为 NaN df[temperature] ( df[temperature] .astype(str) .str.replace(℃, , regexFalse) .str.extract(r(-?\d\.?\d*))[0] .astype(float) ) # 去重同一城市同一更新时间只保留一条 df df.drop_duplicates(subset[city, update_time]) # 缺失值处理这里直接删除也可以按项目需要填充 df df.dropna(subset[temperature, weather]) return df这里用str.extract正则把数字部分提取出来比较稳健。如果页面返回的是 JSON 数字类型那这步可以简化。5.2 保存为 CSV保存 CSV 时建议指定utf-8-sig编码这样用 Excel 打开中文不会乱码def save_to_csv(df: pd.DataFrame, path: str data/weather.csv): df.to_csv(path, indexFalse, encodingutf-8-sig) print(f已保存 {len(df)} 条记录到 {path})如果要进一步扩展也可以把数据写入 SQLiteimport sqlite3 conn sqlite3.connect(data/weather.db) df.to_sql(weather, conn, if_existsreplace, indexFalse) conn.close()CSV 在课程设计中已经够用。如果项目要求体现“数据持久化”SQLite 可以作为一个加分项。6. 数据可视化绘制天气轮播图可视化是项目的展示层。这里推荐用 pyecharts因为生成的是 HTML 页面不需要本地 GUI 环境交互体验也比 matplotlib 更接近现代 Web 图表。6.1 单日天气柱状图先用一次记录生成一个简单的柱状图验证数据能正常传进图表from pyecharts.charts import Bar from pyecharts import options as opts def create_weather_bar(record: pd.Series) - Bar: bar ( Bar() .add_xaxis([温度, 湿度, 风力]) .add_yaxis( 天气指标, [record.get(temperature, 0), record.get(humidity, 0), record.get(wind, 0)], ) .set_global_opts( title_optsopts.TitleOpts(titlef{record.get(city, )}天气), yaxis_optsopts.AxisOpts(name数值), ) ) return bar这里要注意湿度是百分比数值温度是摄氏度风力可能是“3级”这类文本。如果字段类型不统一画图前需要做转换。教学演示时可以把风力转换成等级数值或者在图上单独说明。6.2 Timeline 天气轮播图轮播图的核心是 pyecharts 的 Timeline。把每天的数据作为一页然后按时间顺序轮播展示from pyecharts.charts import Timeline def create_weather_timeline(df: pd.DataFrame, output_path: str output/weather_timeline.html): tl Timeline() tl.add_schema( play_interval1500, is_auto_playTrue, is_loop_playTrue, is_timeline_showTrue, ) # 按日期分组每一天生成一页 for date, group in df.groupby(date): page ( Bar() .add_xaxis(group[city].tolist()) .add_yaxis(温度℃, group[temperature].round(1).tolist()) .add_yaxis(湿度%, group[humidity].round(1).tolist()) .set_global_opts( title_optsopts.TitleOpts(titlef{date} 城市天气对比), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate30)), ) ) tl.add(page, time_pointstr(date)) tl.render(output_path) print(f天气轮播图已生成{output_path})add_schema里的参数决定了轮播效果play_interval播放间隔单位毫秒。is_auto_play是否自动播放。is_loop_play是否循环播放。is_timeline_show是否显示时间轴组件。实际运行前要注意数据结构。如果date列不存在需要先在清洗阶段生成。这里使用的date字段是示例字段项目里可以根据爬取结果改成update_time或today等字段。6.3 结合 matplotlib 做静态图输出如果答辩时不想依赖浏览器或 HTML也可以加一张静态图保存成 PNG当作截图放到文档里import matplotlib.pyplot as plt def create_static_chart(df: pd.DataFrame, output_path: str output/weather_static.png): plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(10, 5)) for city, group in df.groupby(city): ax.plot(group[date], group[temperature], markero, labelcity) ax.set_xlabel(日期) ax.set_ylabel(温度℃) ax.set_title(近期温度变化趋势) ax.legend() ax.grid(True, linestyle--, alpha0.5) fig.autofmt_xdate(rotation45) plt.tight_layout() plt.savefig(output_path, dpi150) plt.close() print(f静态图表已保存{output_path})matplotlib 画中文图时经常遇到字体缺失导致方框乱码。Windows 通常用 SimHei 或 Microsoft YaHeimacOS 建议改为 PingFang SC 或 Arial Unicode MS。这一步很容易遗漏值得在项目文档里标注。7. 项目功能测试与效果验证写完代码不能直接交作业至少要把数据流跑通一遍。下面给出一套通用验证流程。7.1 测试流程表测试阶段操作预期结果判断标准依赖检查pip list 查看库是否安装出现 requests、bs4、pandas、pyecharts版本号存在即可单城市爬取运行爬虫函数抓取一个城市打印出该城市天气信息非空字段完整多城市爬取运行 batch_fetch多个城市依次输出结果没有明显异常信息CSV 存储执行 save_to_csv生成 weather.csvExcel 打开中文不乱码DataFrame 清洗执行 cleantemperature 为数值类型dtype 为 float/int轮播图生成执行 create_weather_timeline生成 html 文件浏览器播放正常静态图生成执行 create_static_chart生成 PNG中文标题和坐标轴显示正常7.2 验证建议第一次运行可视化时先用 2 个城市、3 天数据的规模做测试。如果数据量太大可以先从 CSV 文件读取不需要重新爬取这样调试图表时能省掉请求等待时间。一个很实用的调试思路是“数据不到图表层不查图表”。如果轮播图显示空白先检查 DataFrame 是否为空再检查字段名是否与代码一致最后才排查 pyecharts 配置。很多问题不是图表写错了而是数据列名对不上。7.3 常见现象说明运行脚本后如果看到Process finished with exit code 0只说明程序正常结束不代表逻辑正确。要想看到详细过程必须在脚本里加print输出关键节点比如请求状态码、解析到的字段数量、保存文件路径。这个习惯在项目答辩时也很加分。8. 批量任务与运行策略爬虫天然适合批量处理期末项目里可以加入“定时抓取”和“增量追加”两种策略。8.1 多城市多日期批量抓取在批量抓取基础上可以按日期范围扩展from datetime import datetime, timedelta def build_date_range(days: int 7) - list[str]: today datetime.now() return [(today - timedelta(daysi)).strftime(%Y-%m-%d) for i in range(days)] def batch_fetch_by_dates(cities: list[str], dates: list[str]) - list[dict]: results [] for city in cities: for date in dates: # 注意实际请求参数要按数据源支持的方式传递 params {city: city, date: date} try: html fetch_weather_data(city) data parse_weather_html(html, city) data[date] date results.append(data) except Exception as e: print(f[FAIL] {city}-{date}: {e}) time.sleep(1.5) return results这个循环体里有明显的时间成本。城市数和天数越多总耗时越长所以后台运行时最好打印进度。8.2 增量存储如果程序每天运行一次不应该重复生成整个 CSV而是先读取旧数据追加新数据再整体去重import os def append_to_csv(new_df: pd.DataFrame, path: str data/weather.csv): if os.path.exists(path): old_df pd.read_csv(path) merged pd.concat([old_df, new_df], ignore_indexTrue) merged merged.drop_duplicates(subset[city, date, temperature]) else: merged new_df merged.to_csv(path, indexFalse, encodingutf-8-sig)增量存储的细节不多但能体现对工程化设计的理解。8.3 定时运行Windows 可以用“任务计划程序”macOS 和 Linux 可以用 crontab。例如每天 8 点运行0 8 * * * cd /path/to/weather_project python crawler.py在课程设计中可以把这段写成说明文档不需要真的配置到服务器。重点是让评委知道你有批量任务意识。9. 资源占用与性能观察很多人在运行爬虫和可视化时会忽略性能观察但面试或答辩时这反而是加分点。9.1 CPU 与内存占用爬虫阶段的主要开销在网络请求和 HTML 解析。单线程脚本 CPU 占用一般很低内存占用会根据页面大小波动。如果页面很大且没有设置超时脚本可能长时间卡住所以要格外重视timeout参数。9.2 爬虫速度控制批量抓取速度主要由延时和网络环境决定。把time.sleep从 1 秒改成 3 秒总耗时会被放大。建议不要为了赶时间把延时设得太低平滑的请求节奏比速度更重要。9.3 可视化资源占用pyecharts 生成 HTML 后浏览器在播放轮播图时会加载 echarts.js。如果图表数据点很多页面在弱机器上可能会卡顿。可以限制展示的城市数量或者在分组展示时只选取前 10 个城市。查看资源占用的方法很简单Windows打开任务管理器查看 Python 进程的 CPU 和内存。macOS活动监视器。Linuxtop或htop。只要记录下运行前和运行后的占用值就可以在文档中写“本次测试数据规模为 X 条运行内存约 X MB”。注意数字要真实不要编造。10. 常见问题与排查方法这个项目常见的坑集中在中文字体、字段解析、库版本不兼容和爬虫被拦截。下面列出排查清单。问题现象可能原因排查方式解决方案爬虫返回空白或报 403缺少 User-Agent 或目标站反爬打印状态码和响应前 200 字补全请求头降低请求频率中文乱码编码判断错误打印 resp.encoding 和页面 charset使用resp.apparent_encoding或指定 utf-8/gbkselect_one 返回 None页面选择器变了打开网页源码检查 class修正选择器或改用其他稳定节点Process finished with exit code 0 但无输出脚本没有打印关键信息检查代码逻辑增加 print 输出节点pyecharts 生成 html 后打不开浏览器未正确加载 JS检查文件路径和浏览器用 Chrome 或 Edge 打开本地文件matplotlib 中文乱码缺少中文字体打印可用字体配置 SimHei 或 Microsoft YaHei轮播图只有一页Timeline 循环只添加了一次检查 groupby 循环确认要播放的时间点数量批量任务中途失败某城市请求超时看异常堆栈单请求重试 2 次失败后记录日志继续多次运行数据重复每次都覆盖写 CSV查看保存逻辑改为增量追加并去重pip 安装失败网络或版本冲突查看 pip 错误信息使用镜像源安装表里已经覆盖了这个项目的大部分异常。还有一个容易被忽略的坑在 PyCharm 里运行脚本时如果读取 CSV 文件报找不到路径通常不是文件不存在而是“当前工作目录”不是项目根目录。解决办法是用绝对路径或者在运行时把 PyCharm 的 Working directory 设置为项目根目录。11. 最佳实践与合规提醒到这里整个项目的代码链路已经完整了。最后补充一些工程化建议。第一先小规模验证再扩大数据范围。第一次运行只爬 1 个城市、2 天数据走通全流程后再增加城市数和天数。这样可以快速定位是爬虫问题还是可视化问题。第二用配置分离“数据源地址”和“业务逻辑”。尽量把 URL、Headers、城市列表、延时时间放在文件顶部或一个config.py中不要散落在一堆函数里。答辩时这样做也很容易讲清楚。第三保留一份requirements.txt。这个文件能让别人一条命令安装全部依赖requests2.28.0 beautifulsoup44.11.0 lxml4.9.0 pandas1.5.0 pyecharts2.0.0 matplotlib3.6.0然后在命令行执行pip install -r requirements.txt第四关于合规。爬虫只能访问公开、允许访问的页面或接口。不要在请求头里伪造过度的身份信息不要绕过登录验证不要以高并发抓取任何网站。课程设计要展示技术能力但不能以破坏他人服务为前提。第五涉及天气数据展示时可以加一句“数据仅供学习演示非实时官方数据”。这能避免因数据时效性带来的误解。12. 总结与下一步这个项目最值得尝试的点是把爬虫、数据清洗、存储、可视化四个能力完整串起来。你先验证爬虫能否拿到数据再做清洗和存储最后用 pyecharts 生成天气轮播图。整套流程跑通之后你不仅完成了期末大作业也对 Python 数据项目的常见结构有了实际认识。最优先验证的功能是单城市天气爬取这是整个链路的地基。如果这一步失败后面的清洗和可视化都没有数据来源。最容易踩的坑则是页面选择器变化和中文乱码代码里要对这两个位置做足够的容错和打印日志。后续可以扩展的方向很多把天气数据接入 Flask 或 FastAPI做一个简单的天气查询服务。增加更多可视化图表比如折线趋势图、雷达图、热力图。使用定时任务自动抓取形成历史天气趋势数据集。加入邮件或企业微信通知每天推送天气提醒。项目结构从爬虫到展示已经成形剩下的扩展主要看你想往 Web 开发方向走还是往数据分析方向走。建议先把这个天气轮播图项目完整跑通再逐步替换数据源和图表类型。你需要的就是把示例代码中的 URL、选择器和字段名替换成自己项目实际可用的数据源然后一步步跑通全流程。这样整篇代码和文档都能自洽期末答辩时也能讲得清楚。