ARTICLE DETAIL

资讯详情

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

Python天气查询小程序开发实战:从命令行到微信小程序

Python天气查询小程序开发实战:从命令行到微信小程序 简介一款用 Python 实现的天气查询小程序压缩包面向初学 Python、希望了解网络请求与 API 调用的开发者。程序在命令行中运行默认查询北京也可通过命令行参数指定城市查询时利用 requests 库向天气 API 发送 HTTP GET 请求再用 json 库把返回的 JSON 数据解析成字典进而提取温度、湿度、风速等实时信息整体流程直观易懂。压缩包为 rar 格式共 2 个文件包含一个脚本文件和一个数据库文件——脚本文件负责完整查询逻辑数据库文件用于维护城市索引等数据代码量适中包体仅约 31KB适合初学者直接阅读和动手修改。已有459人学习下载除了核心查询逻辑程序还演示了命令行参数传递、基础错误处理可在此基础上增加天气图标、多城市轮询、定时提醒甚至替换为其他天气 API 或开发图形界面。对想掌握“获取数据—解析数据—展示结果”这条完整链路的 Python 新手来说是一份不错的实战参考。 不用怀疑Python写的天气查询小程序这个项目几乎是每个Python入门者都绕不开的一个经典练习。我之前带过不少新人发现大家练手项目往往卡在两个极端要么是毫无意义的打印九九乘法表要么是一上来就啃爬虫、写框架结果被各种报错劝退。天气查询正好卡在中间它的数据获取涉及网络请求数据处理涉及JSON解析用户交互涉及参数传递但整个逻辑又不复杂一个文件就能写完。这篇内容我会从项目功能设计、数据源选型、代码实现到微信小程序对接把完整链路都拆开讲清楚也把那些文档里不会写的坑一并交代了。1. 为什么查天气值得当练手项目麻雀虽小五脏俱全很多人低估了这个项目。表面上看它只是调一个接口然后打印结果但实际上一个完整的天气查询小程序几乎覆盖了Python入门阶段90%的核心知识点。先说技术覆盖面。网络请求要用的requests库是后续所有爬虫和API对接的基础返回的JSON数据处理涉及字典、列表的嵌套操作城市名的参数传递涉及到URL编码和编码格式处理用户输入校验和异常处理更是所有真实项目的必备环节。如果再加一点代码组织上的思考把API地址、请求参数、数据解析封装成函数你甚至能提前感受到模块化的工程思维。再说成就感。我见过很多初学者写完一个能用的天气查询工具之后那种我真的做出来一个能用的东西的正反馈远比刷十遍教程来得强烈。而且这个项目有天然的延展空间加一个图形界面就成了桌面工具包装成接口就成了小程序后端的雏形甚至还能顺势把smtplib加进去做一个每天自动推送天气到邮箱的自动化脚本。所以我的建议是如果你想学Python但一直没找到合适的练手项目或者想验证自己基础语法掌握得怎么样从天气查询入手是最快、最稳的路径。下面我会把从0到1的完整过程写出来包括我怎么选数据源、怎么写第一版代码、怎么踩坑修坑以及最后怎么把它变成一个小程序接口全部是实操过的东西。2. 数据源选型免费天气API和爬虫方案的取舍写天气查询小程序的第一步不是写代码而是先解决一个关键问题天气数据从哪来这一步选型选错了后面的所有工作都会返工。我前前后后试过多种方案这里把我的踩坑经历和对比结论分享出来。2.1 免费天气API的真实体验市面上常用的免费天气接口我实测过的主要有这几个API免费额度返回格式稳定性备注OpenWeatherMap1000次/天JSON稳定需要英文城市名国内城市不够友好和风天气按开发版套餐JSON稳定国内城市支持好注册审核较严格高德地图天气API部分免费额度JSON稳定需要先申请Web服务Key无天气图标心知天气按套餐JSON一般免费版返回字段少偶尔限流明显先说结论如果你人在国内优先考虑高德地图天气API或者和风天气。高德的优势是申请门槛低、文档清晰而且用的是国内标准城市编码adcode对中文城市名的支持很友好和风天气的数据维度更丰富比如逐小时预报、生活指数、空气质量等但免费条件下字段有限制。OpenWeatherMap虽然国际通用但它默认返回的城市名是英文比如你请求北京它不认识得用Beijing或者经纬度来查。这个问题在开发测试阶段特别容易卡住我第一次用的时候就被绕晕了还得单独维护一套中英文城市名对照表实在麻烦。2.2 为什么不推荐直接爬网站数据有的教程会教你去爬中国天气网的HTML页面用BeautifulSoup解析里面的温度、风力。这种方案从我实测的角度来看基本属于自找麻烦。原因有三个。第一网页结构说变就变今天写好的解析逻辑明天网站前端一改版就全部失效。第二大部分天气网站有反爬策略请求频率稍微高一点就弹验证码你得不停地维护Cookie和Headers。第三没有任何使用条款支持你拿网站的页面数据去做二次分发后续想做成小程序上线随时有合规风险。当然如果纯粹是为了练习requests和BeautifulSoup的配合找一些公开的、允许爬取的页面练手是可以的但那属于爬虫学习项目和今天说的天气查询小程序是两个方向。做工具选API练爬虫选页面千万别混着来。2.3 我最终选型的思路我最终选的是高德地图天气API核心原因是它解决了三个痛点城市名中文输入直接可用、不需要复杂的OAuth签名流程、返回字段完全够用。它的请求方式非常简单用GET请求拼接参数就行。城市的标识用的是adcode比如北京是110000上海是310000。但用户不可能背adcode所以实际开发中需要先从用户输入的中文城市名反查adcode这就要用到高德的另一个接口——地理编码API。一张请求垫一次地理编码再垫一次天气查询就能拿到结构化天气数据了。这里有一个从实际操作中总结的经验高德Web服务Key的申请秒批但每个Key默认有QPS限制开发和测试阶段通常够用但如果要给很多人用建议在代码里加上一个本地缓存机制避免每个用户每次打开都重复请求天气接口。具体怎么加缓存我在后面的代码部分会详细说明。3. 第一版命令行程序从请求到解析的完整链路确定了数据源就可以写第一版代码了。这版的目标很明确在终端里输入城市名程序回显当前天气、温度和风力。虽然界面简陋但整个数据链路是完整的先跑通再美化。3.1 基础环境准备我用的是Python 3.8以上的版本requests库需要单独安装。如果你还没装打开终端执行下面这行命令pip install requests如果你在安装过程中遇到权限问题macOS或Linux上比较常见可以加--user参数或者用虚拟环境venvpython -m venv weather_env source weather_env/bin/activate # Windows下是 weather_env\Scripts\activate pip install requests虚拟环境这个习惯建议从一开始就养成别图省事直接装到全局。我见过太多人因为全局环境的包版本冲突导致一个项目跑不起来连带其他项目也挂了。从第一个练手项目开始就用虚拟环境后面会少很多麻烦。3.2 获取城市编码的代码实现高德天气API需要adcode所以第一步是先根据城市名获取adcode。调用的是高德的地理编码接口import requests def get_adcode(city_name): url https://restapi.amap.com/v3/geocode/geo params { key: 你的高德Web服务Key, address: city_name } try: resp requests.get(url, paramsparams, timeout10) data resp.json() if data[status] 1 and data[geocodes]: return data[geocodes][0][adcode] else: return None except requests.exceptions.RequestException as e: print(f地理编码请求失败{e}) return None这段代码里有两个细节值得说。一是timeout参数requests.get如果不传这个参数在某些极端网络情况下会一直挂着不返回表现为程序卡死加了timeout10就相当于给请求上了个10秒的闹钟。二是resp.json()的调用它会自动把接口返回的JSON字符串解析成Python字典这个过程如果返回内容不是合法JSON会抛异常所以我在外层套了try...except。3.3 天气查询与信息提取拿到adcode之后就可以正式请求天气数据了def get_weather(adcode): url https://restapi.amap.com/v3/weather/weatherInfo params { key: 你的高德Web服务Key, city: adcode, extensions: base # base返回实时天气all返回预报信息 } try: resp requests.get(url, paramsparams, timeout10) data resp.json() if data[status] 1 and data[lives]: weather data[lives][0] return weather else: return None except requests.exceptions.RequestException as e: print(f天气请求失败{e}) return Noneextensions参数是这里的一个优化点。base模式只返回实时天气数据量小、响应快all模式会带上未来几天的预报数据量大一些。命令行版用base就够了但后续如果要做小程序展示未来几天天气就需要改成all。解析出来的weather是个字典里面包含这几个有用字段province和city省份和城市名weather天气现象比如晴多云小雨temperature实时温度单位是摄氏度winddirection和windpower风向和风力等级humidity湿度这个字段在base模式下通常也有reporttime数据发布时间3.4 把用户输入和结果输出串起来主程序逻辑比较简单先获取用户输入的城市名再依次调用两个函数最后打印结果def main(): city_name input(请输入城市名例如北京).strip() if not city_name: print(城市名不能为空) return adcode get_adcode(city_name) if not adcode: print(f未找到城市{city_name}) return weather get_weather(adcode) if not weather: print(获取天气信息失败请稍后再试) return print(f{weather[city]}当前天气{weather[weather]}) print(f温度{weather[temperature]}℃) print(f风向{weather[winddirection]}风力{weather[windpower]}级) print(f湿度{weather[humidity]}%) print(f数据发布时间{weather[reporttime]}) if __name__ __main__: main()strip()方法必须加上。用户输入北京和北京 在肉眼看来差不多但程序会当成两个不同的字符串处理不加strip()会导致查不到数据。这类用户输入的边缘情况才是实战项目里最考验代码健壮性的地方。运行一下效果大概是这样的请输入城市名例如北京上海 上海当前天气多云 温度22℃ 风向东南风风力3级 湿度75% 数据发布时间2024-11-12 14:00:00到这里一个能用的命令行天气查询工具就完成了。如果你只是练手到这一步已经算小有所成。但如果你想把成果分享给朋友用或者进一步做成小程序命令行显然不够友好接下来就要考虑界面或者接口问题了。4. 交互升级给程序加一个像样的入口命令行程序虽然功能完整但显然不够小程序。这里我推荐两条路线你可以根据自己的精力选一条一是用Python自带的tkinter搭一个桌面小程序零额外依赖二是用Python写后端接口前端用微信小程序原生框架来对接。两条路我都走过先讲桌面版因为它的工作量最小能更快让你体会到一个完整的交互闭环。4.1 tkinter桌面版的界面逻辑tkinter是Python自带的GUI库不需要额外安装。界面做起来也很直白一个输入框、一个查询按钮、一块显示结果的文本框。import tkinter as tk from tkinter import messagebox def query_weather(): city entry_city.get().strip() if not city: messagebox.showwarning(提示, 请输入城市名) return adcode get_adcode(city) if not adcode: messagebox.showerror(错误, f未找到城市{city}) return weather get_weather(adcode) if not weather: messagebox.showerror(错误, 获取天气信息失败) return result_text.delete(1.0, tk.END) result_text.insert(tk.END, f城市{weather[city]}\n f天气{weather[weather]}\n f温度{weather[temperature]}℃\n f风向{weather[winddirection]}风力{weather[windpower]}级\n f湿度{weather[humidity]}%\n f发布时间{weather[reporttime]})界面的布局用pack或者grid都行我习惯用grid因为可以精确控制行列对齐。把输入框放第一行、按钮放第二行、结果文本框占满剩余空间一个基本可用的桌面工具就出来了。说一个实操细节如果点击查询按钮后界面卡住不动、过几秒才出结果那是因为网络请求是在主线程执行的阻塞了界面刷新。解决方法是把网络请求放到子线程里。Python里最简单的方式是threading.Thread(targetquery_weather, daemonTrue).start()然后用after方法安全地把结果更新到界面控件上。这个优化虽然不影响功能但直接影响使用体验建议有精力的话做一下。4.2 走向微信小程序的两种姿势如果你最终想做的是微信小程序那么有两种姿势我分别说一下的优劣。一种是前端小程序 Python后端的完整架构。小程序端用wx.request请求你的Python后端接口Python后端去调高德API然后把解析好的JSON返回给前端。这种方式的优点是安全因为高德的Key只放在后端不会被小程序前端抓包泄露功能也更好扩展比如后续要加数据库存历史记录、加定时推送都很方便。缺点是你需要一个公网可以访问的服务器以及一个小程序后端接口才能正式上线。另一种是小程序前端直连高德API。这种做起来最快但高德的Key是明文写在微信小程序代码里的一旦发布别人就可以从代码包里提取你的Key去刷接口到时候产生的费用和封禁风险得你自己兜着。微信小程序上线审核时也会检查网络安全合规性明文暴露Key本身就不是一个规范的实践。所以我的建议很明确做小程序就走前后端分离。Python后端用Flask或FastAPI写一个简单的天气查询接口小程序端负责展示。这样既符合小程序平台的安全审查要求又避免了Key泄漏风险。4.3 一个可以直接用的Flask天气接口下面这个Flask接口是我在实际项目中用的简化版。它接收城市名作为参数返回JSON格式的天气数据from flask import Flask, request, jsonify app Flask(__name__) app.route(/weather, methods[GET]) def weather_api(): city request.args.get(city, ).strip() if not city: return jsonify({code: 1, msg: 缺少城市参数}) adcode get_adcode(city) if not adcode: return jsonify({code: 1, msg: f未找到城市{city}}) weather get_weather(adcode) if not weather: return jsonify({code: 1, msg: 获取天气数据失败}) return jsonify({ code: 0, data: weather }) if __name__ __main__: app.run(host0.0.0.0, port5000)运行这个接口需要先安装flaskpip install flask然后在浏览器里访问http://127.0.0.1:5000/weather?city北京就能看到JSON格式的天气数据了。小程序端只需要用wx.request请求这个地址再把返回的数据渲染到页面上即可。这里再分享一个优化经验给接口加一个内存缓存。因为天气数据的时效性是有限的同一个城市5分钟内的查询结果基本不会有变化与其每次请求都去调高德API不如存到一个字典里过期再更新。下面是简化版缓存逻辑from datetime import datetime, timedelta CACHE {} def get_weather_cached(adcode): now datetime.now() if adcode in CACHE: cached_time, cached_data CACHE[adcode] if now - cached_time timedelta(minutes10): return cached_data data get_weather(adcode) if data: CACHE[adcode] (now, data) return data加了缓存之后高德API的调用量会显著降低接口响应速度也会快很多这个优化在部署到公网服务器之后尤其重要。5. 小程序部分微信小程序前端怎么对接这个接口如果你走到了这一步说明你想要的已经不只是Python写的天气查询小程序这个标签而是真正想让它在手机上能跑起来。微信小程序前端对接Python后端核心就是两点发起请求、渲染数据。5.1 小程序的请求封装在小程序的index.js文件里写好天气查询的请求逻辑Page({ data: { city: , weather: null, loading: false }, handleInput(e) { this.setData({ city: e.detail.value }); }, queryWeather() { const city this.data.city.trim(); if (!city) { wx.showToast({ title: 请输入城市名, icon: none }); return; } this.setData({ loading: true }); wx.request({ url: http://your-server.com/weather, data: { city: city }, method: GET, success: (res) { if (res.data.code 0) { this.setData({ weather: res.data.data }); } else { wx.showToast({ title: res.data.msg, icon: none }); } }, fail: () { wx.showToast({ title: 网络请求失败, icon: none }); }, complete: () { this.setData({ loading: false }); } }); } })这里有个微信小程序的硬性要求正式上线时接口域名必须是备案过的HTTPS域名http://明文IP地址在开发工具里开不校验合法域名选项能临时调试但真机预览和线上环境会被拦。如果只是本地调试用微信开发者工具勾选不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书就可以先跑起来上线的准备工作另说。5.2 页面渲染与换一个思路index.wxml直接展示从后端拿到的数据即可view input placeholder请输入城市名 bindinputhandleInput / button bindtapqueryWeather查询天气/button /view view classweather-card wx:if{{weather}} view城市{{weather.city}}/view view天气{{weather.weather}}/view view温度{{weather.temperature}}℃/view view风向{{weather.winddirection}} {{weather.windpower}}级/view view湿度{{weather.humidity}}%/view /view除了这种传统的查询交互还有一个值得尝试的方向让用户授权地理位置然后根据经纬度自动查询当地天气。高德API支持从经纬度反查adcode这样用户打开小程序就能直接看到当前城市的天气不需要手动输入。这个方案看似只改动了一小步但从用户实际使用的角度看是从主动查到打开就有的体验升级。对应的后端接口也需要加上一个支持经纬度参数的查询逻辑。6. 实测中的坑限流、缓存和免费API的生存法则最后聊几个我在实际使用中踩过的坑这些都是文档里不会系统讲、但真实项目中几乎必然遇到的问题。6.1 请求限流是常态免费API普遍都有QPS限制。高德Web服务默认大概是每秒3次一旦超过就返回错误码CUQPS_HAS_EXCEEDED_THE_LIMIT。最开始我没有缓存机制的时候本地开个多线程测试很快就把自己限制住了。解决方案就是我前面说的缓存 控制请求频率。工具类代码不像高并发服务把请求频率控制在1次/秒以内基本不会触发限制。6.2 中文参数必须做URL编码当你直接用requests.get(url, paramsparams)传中文城市名时requests库会自动帮你做URL编码一般不会出问题。但如果你看到报错UnicodeEncodeError或者请求返回的数据明显不对大概率是编码出了问题。尤其是你手动拼URL字符串的时候一定要用urllib.parse.quote对中文参数做编码。这个坑在从用requests库传参切换到手动拼接URL的时候特别容易出现。6.3 自定义接口别裸奔上线如果你把Flask接口部署到公网服务器一定要做两个基础防护一是隐藏或不透传高德Key确认Key只存在后端环境变量里二是给接口加一个简单的访问频率限制防止被恶意循环调用。Flask里可以用Flask-Limiter这个库来实现。不然一台小服务器的带宽和免费API的额度很快就会被刷光。6.4 预报数据比实时数据更受用户欢迎我做第一版的时候只展示了实时天气。后来给朋友试用大家问得最多的反而是明天还下不下雨——这说明对普通用户来说预报信息比当前温度更实用。高德的extensionsall参数能返回3天预报字段里包含casts数组每个元素包含date、dayweather、nightweather、daytemp、nighttemp等字段。建议你在后端接口里把实时数据和预报数据一并返回前端用Tab或者卡片切换展示用户体感会完全不一样。6.5 日志记录一定要早点加我第一次部署到服务器上发现接口偶尔会超时但不知道是哪个环节的问题因为没有日志。后来加了Python的logging模块把每个请求的城市名、adcode、高德API响应状态、耗时都记录下来定位问题就容易多了。这里分享一个简单配置import logging logging.basicConfig( levellogging.INFO, format%(asctime)s %(levelname)s %(message)s, handlers[ logging.FileHandler(app.log), logging.StreamHandler() ] ) logger logging.getLogger(__name__) # 在请求时记录 logger.info(fcity{city}, adcode{adcode}, cost{cost_time}s)别小看这几行日志排查线上问题的时候它是最直接的证据来源。回头再看这个项目从命令行工具、桌面程序再到小程序后端技术栈不断叠加但核心始终没有变先解决数据获取再解决交互展示。你现在用到的请求、解析、异常处理、接口设计、缓存优化每一项在后面做更复杂的项目时都会反复用到。如果接下来想继续进阶可以考虑给小程序加上每早定时推送天气的服务端任务或者用图表展示未来一周的气温曲线这些都是基于现有项目的自然延伸。本文还有配套的精品资源点击获取
返回列表