🙋♀️ 本期工具展示

🔍 背景
做桥梁健康监测相关工作。大型桥梁上会布置各类传感器,持续采集结构状态数据——温度、温湿度、车辆荷载、船撞冲击等等。这些数据需要定期下载、分析,整理成报告交付给业主。
需要处理的桥梁不止一座,数据种类也不少。
拿到API和配置表之前
以前没有API,数据只能通过平台网页操作。出报告时主要靠两种方式。
一种是手动下载数据再自己分析:
> 打开数据平台 → 选桥梁A → 选"温湿度" → 填开始日期 → 填结束日期 → 点下载 → 等待 → 保存 → 选"车辆荷载" → 重复上面所有步骤 → 切换到桥梁B,继续重复……。
另一种是直接在平台上截图——平台本身是给业主实时查看数据用的,上面有现成的图表界面。一张一张切换、截图、粘贴进报告,省去了自己跑分析的步骤。但截图数量非常多,同样是机械重复操作;更麻烦的是,平台只展示图形,遇到需要统计具体数值的地方——比如某段时间内的温度最高值是多少——还得眼睛盯着图表自己去读,既不准确,也费眼睛。
两种方式都能出报告,但都谈不上高效,大量时间花在了跟分析本身无关的地方。
后来去找软件组同事要来的两样东西
一是**API接口**。有了API,数据可以用代码直接拉取,不需要再打开前端平台操作——无论是手动下载还是截图,都不再需要了。数据从API拉进来之后,自己画图、自己统计、自己生成报告,图表样式和统计口径完全可控,不依赖平台界面呈现什么就截什么。
二是**Excel配置表**。这张表是整个自动化真正能跑起来的基础——里面记录了所有桥梁的完整信息,按数据类型分工作表存放:每座桥下有哪些测点、测点名称、测点ID、通道号、数据类型、量程、单位……所有跟测点有关的配置都在里面。API请求需要用到这些ID和参数,没有这张表,程序不知道要去请求什么,API就是空的。
这两样东西配合起来,自动化才真正有了基础。
----------
💡 解决思路
核心目标是把这条流程尽量压缩到"配置一次,一键执行":
- 在配置文件里声明:下哪些对象、哪些数据类型、哪个时间段
- 程序自动完成下载、分析
- 输出报告(各模块目前已能单独输出Word,整合工作还在进行中)
----------
## 01 整体架构
config.py ← 所有参数集中配置downloaders/ ← 各数据类型的下载器analyzers/ ← 各数据类型的分析器main_downloader.py ← 下载统一调度入口main_analyzer.py ← 分析统一调度入口unified_gui.py ← 图形界面
最初是散装脚本——下温湿度一个py,下车辆荷载一个py,各自维护各自的路径和参数。每次改时间范围,要开三个文件分别改。
重构之后的原则是:**配置只写一次,所有模块来读它,改一处全部生效**。
----------
## 02 Excel配置表驱动的界面搜索
有了这张Excel配置表,界面上的桥梁选择就不需要每次手动改代码了。
程序启动时会读取配置表,把所有桥梁名称加载进界面的桥梁列表。上方有一个搜索框,直接输入关键字就能过滤——配置表里有多少座桥,搜索范围就有多大,不需要提前知道全部桥名。
勾选想要处理的桥梁,选中的自动置顶显示,再配合数据类型和时间范围,点"开始下载",程序去Excel里查对应的测点ID和参数,组装API请求,批量拉取数据。
整个过程不需要改任何代码,也不需要记住测点ID是什么。配置表维护好,界面操作就够用了。
----------
## 03 界面设计
三个标签页,分别对应三个阶段:
**📥 数据下载**:左侧选择对象(支持搜索,选中的自动置顶)、勾选数据类型、填时间范围;右侧实时显示下载日志。
**📊 数据分析**:程序自动扫描已下载的数据,列出所有可分析项目,勾选后一键运行。
**🔬 特殊分析**:非标准的专项功能区——倾角仪数据分析、车流量统计、交互式绘图器等,后续有新需求往里塞。
有两个细节做得比较实用:
**实时日志**:下载在后台线程运行,把 `sys.stdout` 重定向到界面文本框,所有模块里的 `print()` 输出自动显示在日志里,不需要单独写回调。
classLogRedirect:def__init__(self, log_func):self.log_func = log_funcdefwrite(self, text):if text.strip():self.log_func(text.rstrip())sys.stdout =LogRedirect(self.download_log)
**随时可停**:`is_downloading` 标志位控制中断,用户点停止后等当前对象跑完再退出,已完成的数据完整保留。
----------
## 04 下载器调度
每种数据类型对应一个下载器,统一暴露相同的接口:`
defdownload_bridge_data(self, name: str) -> bool: ...for name in bridge_names:if'other' in data_types: self.other_downloader.download_bridge_data(name)if'ship' in data_types: self.ship_downloader.download_bridge_data(name)if'vehicle'in data_types: self.vehicle_downloader.download_bridge_data(name)
新增数据类型只需写一个新下载器,调度器加一行判断,其他不动。
数据下完后按固定目录结构存放:
报告目录/├── 对象A/│ ├── 原始数据/│ │ ├── 车辆荷载/│ │ ├── 船撞/│ │ └── 温湿度/│ └── 分析结果/└── 对象B/└── ...
----------
## 05 分析器调度
各数据类型的分析器来自不同时间、不同人,方法名不统一。为避免大规模改历史代码,调度器采用依次探测的方式:
if hasattr(analyzer,'run_detailed_analysis'): analyzer.run_detailed_analysis()elif hasattr(analyzer,'run_analysis'): analyzer.run_analysis()elif hasattr(analyzer,'run'): analyzer.run()elif hasattr(analyzer,'analyze'): analyzer.analyze()
只要分析器有其中任意一个方法,就能被接入调度。存量代码不需要改,新写的接入也很简单。
----------
报告输出现状
目前各分析器可以独立输出Word文档,包含对应数据类型的图表和统计结果。问题在于**各模块是分开的**——温湿度一份,车辆荷载一份,船撞一份,没有整合成一份完整的报告。只起到协助作用,并没有全自动。
下一步的目标是打通这最后一段:把各模块的分析结果统一汇入同一个报告模板,实现数据下完即出完整报告。🚀
----------
🙋♀️ 作者:leilei
💫 碎碎念学习记录
📅 更新时间:2026年3月
夜雨聆风