乐于分享
好东西不私藏

Python自动化:监测数据下载、分析,到报告输出

Python自动化:监测数据下载、分析,到报告输出

🙋‍♀️ 本期工具展示

🔍 背景

做桥梁健康监测相关工作。大型桥梁上会布置各类传感器,持续采集结构状态数据——温度、温湿度、车辆荷载、船撞冲击等等。这些数据需要定期下载、分析,整理成报告交付给业主。

需要处理的桥梁不止一座,数据种类也不少。

拿到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_func    defwrite(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月