做这个公交查询和失物招领小程序,起因是本地公交 App 的线路更新总滞后,失物招领又分散在各个微信群,效率很低。于是想用 Python 搭个后端,前端就用微信小程序,踩一遍坑。
后端选了 Flask,轻量灵活,团队里有人更熟 Django 的话也能无缝切换。数据库用 MySQL,存公交线路和失物数据够用,MongoDB 在查询聚合上有点优势,但团队运维经验少就没选。前端本来想试试 Uniapp,一套代码多端跑,后来发现有些小程序 API 不太兼容,还是原生开发更稳。
公交查询模块的重点是数据来源。官方开放平台是最理想的,但很多城市还没提供稳定接口。我试过 Scrapy 爬市政公开数据,建了个定时任务更新,但反爬策略一升级就头疼。路径规划用了经典的 Dijkstra 算法,在站点图上计算最低代价路径,换乘惩罚设为路段距离的 1.5 倍。那个公式 \min \sum_{i=1}^{n} (\text{换乘权重} \times \text{路段距离}) 就是个示意,实际权重得根据步行距离和等车时间反复调优。实时到站依赖车载 GPS,我们对接了一个第三方数据源,延迟大概 10 秒,勉强算'实时'。
失物招领子系统比想象中费神。物品登记支持文字和图片上传,手机号等私密信息用 AES 加密再入库。匹配算法最初想上 BERT 做语义相似度,数据量和算力都不够,最后用 TF-IDF 向量求余弦相似度,把丢失物品和拣到物品的描述进行比对,准确率在阈值 0.7 时能到 80% 左右,够用了。匹配成功就通过微信模板消息通知双方,但模板消息限制多,后来换成了订阅消息,点击授权才能推。
接口安全按常见做法:JWT 鉴权,Flask-Limiter 限流防爬,接口参数也做了校验。这些不是什么高深东西,但省掉的话线上出问题就晚了。
性能优化上,Redis 缓存热点查询路线的效果很明显,首页顶部 20 条常用线路的查询耗时从 200ms 降到了 15ms。静态资源本来就不多,丢到 CDN 上进一步减轻服务器负担。数据库读写分离设计了一下,但早期 QPS 都没破 10,单机完全撑得住,就没实际拆。别一上来就过度设计,这是我的教训。
部署用 Docker 打包成镜像,配合 Nginx 反向代理和负载均衡,加个 docker-compose 就起来了。日志用 ELK 收集分析,错误监控上 Sentry,每次报错邮件通知,挺踏实。
测试环节,JMeter 压了几个高频接口,并发 100 时响应时间在可接受范围。Appium 做 UI 自动化测试,但小程序环境不太稳定,跑通率一般,大部分回归还是靠手动点。
后续打算对接智能语音,让用户直接说地址就能查;无障碍出行指引也是刚需,会优先做。第三方开放 API 暂时不考虑,先把核心功能做扎实。
开发流程就是常规的需求分析、功能设计、数据库设计、前后端开发、测试、上线。我们这套技术栈是 Flask + MySQL + Redis + 微信原生 + HBuilderX,但用 Spring Boot、Node.js 或 ThinkPHP 也都能做到,看团队技术储备。工具上,Navicat 管理数据库、微信开发者工具调试界面,没什么新奇。
整个过程踩坑不少,但公交查询和失物招领这两个需求是真需求,数据打通以后确实能帮到人。如果你也在做类似的事,建议优先搞定官方数据源,省掉的开发时间比什么都值。


