ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Python的天气数据爬取与可视化实战:从requests到Tkinter界面

基于Python的天气数据爬取与可视化实战:从requests到Tkinter界面 简介基于Python实现的天气数据爬取与可视化项目面向计算机相关专业在校学生的课程设计、毕业设计及初期立项演示也适合有基础爬虫与可视化学习需求的Python开发者。代码包含详细注释配有界面演示可直观了解从数据抓取、清洗存储到图表展示的完整流程。资源包共20个文件压缩后约393KB核心为3个Python脚本天气数据爬取、两份数据分析与可视化、2个CSV数据文件、1张界面演示截图以及README说明、项目配置和依赖记录等目录结构清晰。已有107人学习下载。项目代码经过测试运行成功答辩评审平均分96分便于直接使用或在原基础上二次开发。通过学习这份资源可以掌握天气类数据的爬取思路、文件读写与可视化方法并借助注释快速理解每段逻辑适合作为课设作业的参考模板或实战练手项目。1. 从课程设计到可运行的天气爬虫可视化程序每年到课程设计季天气数据爬取和可视化就会出现在大量 Python 选题里。你大概率见过这样的同学兴致勃勃调好了爬虫却卡在数据解析上画好了图表却不知道怎么放进界面里演示。其实这个题目真正考的不是“能不能抓到数据”而是你能否把网络请求、HTML 解析、数据清洗、可视化展示四个环节串成一条完整链路并且让代码能被别人看懂。本文就以标题里的“基于 Python 实现简单的天气数据爬取和可视化”为主线写一套可以直接抄、能跑通、注释齐全的完整方案。我会选用 requests BeautifulSoup 抓取公开网页数据用 matplotlib 做可视化再用 Tkinter 做一个最简单的界面演示。这套组合不依赖重型框架环境搭建成本低也足够应付高分课程设计。2. 天气数据爬取的技术选型与反爬边界2.1 数据源选择直接爬网页还是调 API做天气爬取时第一个要拍板的事是数据源。常见做法有两种调天气 API如 OpenWeatherMap、心知天气或者直接爬网页。API 的优点是数据结构化好、字段齐全但通常需要注册 key而且免费额度有限直接爬网页则不需要 key只要目标网站没有强反爬就能用 requests 把页面抓下来再用 BeautifulSoup 解析 HTML。课程设计里我更推荐后者因为你能在报告中写清楚“如何分析请求头”“如何定位 DOM 节点”这些过程才是评分老师愿意看到的内容。我一般会选那种结构稳定的公开天气页面比如中国天气网的某个城市页面或者 wttr.in 这类极简风格的天气服务它们的 HTML 结构相对固定适合做教学案例。2.2 requests BeautifulSoup 的解析模型与反爬识别拿到一个网页以后爬虫的核心就两件事发请求、解析响应。requests 负责把 HTTP 请求发出去BeautifulSoup 负责把返回的 HTML 字符串变成一棵可遍历的树。这两者组合的解析模型是先soup.find()定位目标节点再用.text取出文本用.get(属性)取出标签属性。实际爬取时很多页面会校验请求头里的 User-Agent甚至校验 Referer、Cookie。如果直接发裸请求大概率只能拿到一个 403 或者一个登录跳转页面。所以我一般会在请求头里带上浏览器信息必要时再加一个间隔等待。下面是一张常用的请求头参数表也是你调参时重点看的几个字段。参数名典型值作用User-AgentMozilla/5.0 ...标识客户端类型绕过最简单的 UA 校验Refererhttps://target.com/告诉服务器请求来源部分站点会校验Cookiesessionxxx; ...维持会话状态有些数据需要登录后可见Accept-Languagezh-CN,zh;q0.9让服务器返回中文内容避免乱码2.3 频率控制与合规边界爬虫不是请求发得越快越好。对目标站点做高频请求一是容易触发 IP 封禁二是给对方服务器造成压力这个在课程设计里也是忌讳。我一般会在两次请求之间加time.sleep(1)如果数据量小甚至加到 2 秒。另外在代码注释里写清楚数据来源和抓取时间这既是工程习惯也是合规意识的体现。你要在报告中说明仅抓取公开静态页面不碰登录接口不遍历敏感路径不做商业用途。这套方案在课堂上使用没有任何问题但如果你要放到生产环境必须先去查看目标网站的robots.txt确认是否允许爬取。3. 实现天气数据爬虫带详细注释的核心代码3.1 定义数据模型与抓取函数动手写爬虫前先想清楚你要拿哪些字段。一个简单的天气数据模型至少要有日期、最高温、最低温、天气状况、风力这几项。把它们定义成字典后续可视化时直接按 key 取值比用元组或散装变量清晰得多。下面这段代码我写了详细注释你直接复制到项目里就能跑通。import requests from bs4 import BeautifulSoup import time # 数据模型用一个字典保存单日天气信息 def empty_weather(): return { date: , high: 0, low: 0, condition: , wind: } # 核心抓取函数传入目标URL返回解析后的天气列表 def fetch_weather(url, headersNone): if headers is None: headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout10) resp.encoding utf-8 # 大部分中文天气站用utf-8个别用gbk soup BeautifulSoup(resp.text, html.parser) return soup这段代码里requests.get的timeout参数很关键它控制了最长的等待时间避免某个请求卡死整个程序。resp.encoding如果设错了解析出来的中文会变成乱码常见做法是先打印resp.apparent_encoding看一眼再决定。BeautifulSoup的第二个参数指定了解析器html.parser是 Python 标准库自带的不需要额外安装比lxml更省事。3.2 解析 HTML 提取关键字段数据抓下来以后真正的难点是定位 HTML 里的节点。你需要在浏览器里按 F12 找到目标数据的父节点然后写选择器。我用过的最常见的结构是每天的气象信息放在一个ul classt clearfix下每个li对应一天的数据。定位方式有两种.find()只取第一个.find_all()取所有。下面示例演示如何提取 7 天的天气列表并处理空值和单位。def parse_weather(soup): weather_list [] # 定位到包含每日数据的列表容器class名称以实际页面为准 days soup.find_all(li, class_sky skyid) if not days: days soup.select(.t li) # 备选选择器 for day in days[:7]: # 只取前7天控制数据量 item empty_weather() # 日期在h1标签内形如7日今天 date_tag day.find(h1) if date_tag: item[date] date_tag.text.strip() # 高温和低温分开放在两个span里 high_tag day.find(span, class_tem) if high_tag: # 把字符串里的℃去掉转成整数 item[high] int(high_tag.text.replace(℃, ).strip()) low_tag day.find(p, class_tem) if low_tag: item[low] int(low_tag.span.text.replace(℃, ).strip()) # 天气状况在p标签的title属性里 cond_tag day.find(p, class_wea) if cond_tag: item[condition] cond_tag.text.strip() weather_list.append(item) return weather_list这里有两个常见的坑一是class里有多个类名时直接用class_sky skyid这样写匹配的是完整字符串不是子串如果你不确定就改用.select(.sky)二是find_all返回的列表可能包含你不需要的元素比如页脚的重复天气信息所以我才加了[:7]切片只取前 7 天。解析完成后建议立刻打印一条记录看结构对不对再进入下一步。3.3 异常兜底与注释规范写爬虫最容易忽略的是异常处理。网络请求可能超时、返回空页面、甚至目标节点被删改这些都要兜住。我给你一个最小但完整的异常处理模板能覆盖 80% 的失败场景。同时课程设计对注释要求很高我的注释原则是说明“为什么这么做”而不是“这句代码在做什么”这样才能体现你对逻辑的理解。def safe_fetch(url, retries3): for i in range(retries): try: soup fetch_weather(url) return parse_weather(soup) except requests.exceptions.Timeout: # 超时重试等待时间逐次增加 wait (i 1) * 2 print(f[警告] 请求超时{wait}秒后重试) time.sleep(wait) except Exception as e: # 兜底捕获所有异常避免程序崩溃 print(f[错误] 抓取失败{e}) return [] return [] # 重试耗尽返回空列表这段代码的返回值设计很重要失败时返回空列表而不是抛出异常。这样主程序可以继续执行可视化部分至少能显示一个空图或提示信息而不是黑屏退出。retries参数控制重试次数我一般设 3 次再多就是对目标网站不礼貌了。把fetch_weather和parse_weather分开写是为了让每层逻辑独立方便你在报告里分别解释网络层和解析层的设计。4. 可视化与界面演示从数据到图表再到窗口4.1 matplotlib 绘制温度曲线与天气分布拿到 7 天数据后可视化就顺理成章了。最常用的图是温度曲线横轴日期两根折线分别表示最高温和最低温。为了更直观我会把天气状况作为图上的文本标注。matplotlib 的画图逻辑是先准备数据列表再plt.plot()最后plt.show()。下面这段代码可以直接嵌入你的主程序。import matplotlib.pyplot as plt def plot_temperature(weather_list): if not weather_list: print(没有数据无法绘图) return dates [w[date] for w in weather_list] highs [w[high] for w in weather_list] lows [w[low] for w in weather_list] plt.figure(figsize(10, 5)) plt.plot(dates, highs, markero, label最高温) plt.plot(dates, lows, markers, label最低温) # 在最高温折线上方标注天气状况 for i, cond in enumerate([w[condition] for w in weather_list]): plt.text(i, highs[i] 1, cond, hacenter, fontsize9) plt.title(近7天天气趋势) plt.xlabel(日期) plt.ylabel(温度(℃)) plt.legend() plt.grid(True) plt.tight_layout() plt.show()这里marker参数给折线加了数据点标记o是圆形s是方形可视化课设里常用。plt.text的坐标是(x, y)我让y取最高温加 1这样文字不会盖住折线。tight_layout()解决标签被截断的问题这个细节经常被忽略。如果你用的是中文标签一定要在代码开头设置plt.rcParams[font.sans-serif] [SimHei]否则中文会变成方块。4.2 Tkinter 嵌入图表实现界面演示界面演示部分很多同学会考虑 web 框架其实课程设计里我用 Tkinter 就够了。它是 Python 自带的 GUI 库不需要额外安装启动快演示时也不依赖浏览器环境。思路是窗口里放一个按钮和一个画布点击按钮后抓取最新数据并绘图然后把图表保存成图片再显示到窗口里。matplotlib 直接嵌入 Tkinter 需要FigureCanvasTkAgg最简单的是用如下方式。import tkinter as tk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg def show_interface(): root tk.Tk() root.title(天气爬取与可视化演示) # 用于绘制图表的容器 fig plt.Figure(figsize(6, 4)) ax fig.add_subplot(111) canvas FigureCanvasTkAgg(fig, masterroot) canvas.get_tk_widget().pack() def refresh(): # 点击刷新按钮时重新抓取和绘制 data safe_fetch(https://example.com/weather) ax.clear() ax.plot([d[high] for d in data], labelhigh) ax.plot([d[low] for d in data], labellow) ax.legend() canvas.draw() btn tk.Button(root, text刷新数据, commandrefresh) btn.pack() refresh() # 启动时先展示一次 root.mainloop()这段代码演示了按钮绑定事件和 canvas 刷新的核心逻辑。FigureCanvasTkAgg把 matplotlib 的 figure 对象嵌入到 Tk 窗口里每次刷新时调用ax.clear()清空旧图再画新图canvas.draw()更新显示。如果你不想用 Tkinter也可以改用pywebview或Flask做可视化界面但我个人认为 Tkinter 在课设答辩时更稳因为它不需要额外端口和服务配置双击就能运行。4.3 数据持久化与刷新逻辑界面演示不只是看一个静态图表你要让观看者知道数据是“实时抓取”的。所以刷新逻辑非常重要。我一般会加两个功能一是把抓到的数据存成 CSV 文件方便事后核对二是每次刷新前清空旧数据并用状态栏提示“更新完成”。这既能体现你对数据生命周期的理解也能避免答辩时因为缓存问题被追问。写入 CSV 的代码很简单。import csv def save_weather(weather_list, filenameweather.csv): with open(filename, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[date, high, low, condition, wind]) writer.writeheader() writer.writerows(weather_list) print(f数据已保存到 {filename})newline是为了避免 Windows 下 CSV 文件多出空行这个坑很常见。encodingutf-8保留中文不乱码。在界面刷新时先调用safe_fetch再调用save_weather最后更新图表这样你的程序就形成了“抓取-保存-可视化”闭环。5. 进阶技巧验证数据正确性与提高爬虫稳定性5.1 用日志和重试机制替换简单 print你在课设答辩时评委可能会问“你的程序怎么应对目标网站改版”直接的回答是我用了日志和重试。简单的print在代码跑完后什么痕迹都留不下而logging模块能记录到文件方便排查。我一般会做如下替换。import logging logging.basicConfig( filenameweather.log, levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s ) logging.info(开始抓取天气数据)更进一步的稳定性优化是设置请求频率限制把time.sleep(1)改成从配置里读取的间隔值这样你在演示时可以把间隔调小在生产时调大。此外还可以用requests.Session()复用连接减少 TCP 握手次数这个优化在抓取多个页面时效率提升明显。Session 对象会自动保存 cookie某些需要先访问首页获得会话的站点也能正常处理。5.2 3 个验证数据正确性的方法可视化结果是不是可信要看数据源头对不对。我常用三个方法验证爬虫抓到的数据第一打印原始 HTML 片段确认选择的节点没有变化第二把抓到的日期和本地系统日期做对比防止抓到旧数据第三用两个不同网站的数据做交叉对比比如同时抓取同一个城市在两个站点的温度差值在 2 度以内基本可以认为没问题。# 验证HTML节点是否匹配在命令行里直接测试选择器 python -c from bs4 import BeautifulSoup; print(BeautifulSoup(open(page.html, encodingutf-8), html.parser).select_one(.tem).text)如果这条命令能输出温度值说明选择器写的没错。如果输出None说明页面结构变了你需要重新查看 DOM 节点。交叉对比时注意两个站点的更新时间可能不同最好选择同一小时的整点数据避免因为时间差导致误差过大。5.3 从课程设计到工程化的差距课程设计做完后如果你想把它变成能长期跑的小工具还需要补三块配置管理、单元测试、模块解耦。比如把 URL、User-Agent、刷新间隔等抽到一个config.py里而不是写在主程序里为parse_weather写一个简单的测试用例用一段固定的 HTML 字符串验证解析逻辑是否正确。这些做法在课设里是加分项在真实项目里是必备项。最后提醒你一点爬虫代码的注释风格要统一我习惯用中文注释但变量名和函数名用英文这样报告和代码都能兼顾可读性。如果你希望进一步优化界面演示的观感可以在show_interface里加一个下拉框切换城市或者用matplotlib的动画功能让曲线逐段出现这些都能让演示效果更接近正式的成品。本文还有配套的精品资源点击获取
返回列表