电子科大成都学院电费自动化查询
学校电费查询需要通过网页进入电表页面查看。
如果只是偶尔查询没有什么问题,但如果想实现定时查询、低电量提醒或者接入自己的机器人,每次手动打开网页就比较麻烦。
本文记录通过浏览器开发者工具分析电表查询请求,并使用 Node.js 直接获取电表剩余数据的方法。
说明
本文仅记录本人正常使用的电表信息查询过程,用于学习和个人自动化。请勿对学校服务器进行高频请求、批量扫描或查询无权访问的数据。
一、分析电费查询请求
首先正常进入学校的电费查询页面,然后打开浏览器开发者工具:
F12 → Network → Fetch/XHR刷新页面或者重新查询一次电费。
可以观察到浏览器向以下接口发送了一个 POST 请求:
https://www.cduestc.cn/sfxq//kddz/electricmeterpost/electricMeterQuery请求类型:
POST请求的 Content-Type 为:
application/x-www-form-urlencoded二、分析 POST 参数
在浏览器 Network 中查看请求的 Payload / Form Data,可以看到查询主要使用两个参数:
wechatUserIdelectricUserUid例如:
wechatUserId=你的用户IDelectricUserUid=你的电表ID其中:
wechatUserId:当前用户对应的 IDelectricUserUid:电表对应的 ID
这两个值可以通过浏览器开发者工具查看自己的正常查询请求获得。
注意
不建议在公开的 GitHub 仓库或博客中直接发布自己的真实用户标识。本文示例统一使用占位值。
三、接口返回数据
正常查询后,服务器返回 JSON,例如:
{ "msg": "操作成功", "code": 0, "data": { "querycode": "1", "shengyu": "93.21", "zhuangtai": "合闸", "leiji": "6668.51", "querymsg": "双回路表状态查询成功" }}主要字段含义:
| 字段 | 说明 |
|---|---|
code | 接口请求状态 |
shengyu | 电表剩余值 |
zhuangtai | 当前电表状态 |
leiji | 累计值 |
querymsg | 查询结果说明 |
例如:
剩余:93.21状态:合闸累计:6668.51四、关于 H32C6TIi 参数
在浏览器 Network 中观察实际请求时,可以发现 URL 后面还可能自动出现一个很长的参数:
?H32C6TIi=xxxxxxxxxxxxxxxx而且多次刷新页面后,该参数的内容可能发生变化。
最开始我以为查询接口必须携带这个参数,因此尝试分析它的来源。
页面 HTML 中存在额外的安全脚本以及类似:
<meta id="..." content="..." r="m">和:
$_ts = window["$_ts"];$_ts.nsd = ...;$_ts.cd = "...";这样的代码。
同时页面还会加载额外的混淆 JavaScript。
因此,H32C6TIi 更像是网页安全防护层在浏览器请求过程中附加的参数,而不是电表查询业务本身的普通参数。
实际测试
后来尝试完全删除:
H32C6TIi直接向原始接口发送 POST:
POST /sfxq//kddz/electricmeterpost/electricMeterQuery仍然能够正常返回:
{ "msg": "操作成功", "code": 0}因此对于当前的电表查询接口,实际测试发现 无需携带 H32C6TIi 也可以完成正常查询。
这样 Node.js 的实现就简单很多,不需要执行浏览器 JavaScript,也不需要使用 Playwright 模拟完整浏览器。
该行为属于当前测试结果,学校网站后续如果修改接口或安全策略,可能会发生变化。
五、使用 Node.js 查询
Node.js 18+ 已经内置 fetch,因此不需要额外安装 Axios 等 HTTP 库。
新建文件:
electric.mjs写入:
const url = "https://www.cduestc.cn/sfxq//kddz/electricmeterpost/electricMeterQuery";
const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }, body: new URLSearchParams({ wechatUserId: process.env.WECHAT_USER_ID, electricUserUid: process.env.ELECTRIC_USER_UID, }),});
if (!response.ok) { throw new Error(`HTTP ${response.status}`);}
const result = await response.json();
if (result.code !== 0) { throw new Error(result.msg || "电表查询失败");}
console.log(result);六、配置自己的电表信息
为了避免把自己的 ID 直接写进代码,可以通过环境变量传入。
Linux / macOS:
export WECHAT_USER_ID="你的用户ID"export ELECTRIC_USER_UID="你的电表ID"然后运行:
node electric.mjs正常情况下会得到类似:
{ "msg": "操作成功", "code": 0, "data": { "querycode": "1", "shengyu": "93.21", "zhuangtai": "合闸", "leiji": "6668.51", "querymsg": "双回路表状态查询成功" }}七、只输出需要的数据
如果不需要完整 JSON,可以进一步处理返回结果:
const url = "https://www.cduestc.cn/sfxq//kddz/electricmeterpost/electricMeterQuery";
const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }, body: new URLSearchParams({ wechatUserId: process.env.WECHAT_USER_ID, electricUserUid: process.env.ELECTRIC_USER_UID, }),});
if (!response.ok) { throw new Error(`HTTP ${response.status}`);}
const result = await response.json();
if (result.code !== 0) { throw new Error(result.msg || "查询失败");}
const { shengyu, zhuangtai, leiji, querymsg,} = result.data;
console.log(`剩余:${shengyu}`);console.log(`状态:${zhuangtai}`);console.log(`累计:${leiji}`);console.log(`结果:${querymsg}`);运行:
node electric.mjs输出类似:
剩余:93.21状态:合闸累计:6668.51结果:双回路表状态查询成功八、封装成函数
如果后续还需要接入其他程序,可以进一步封装:
async function queryElectricity(wechatUserId, electricUserUid) { const url = "https://www.cduestc.cn/sfxq//kddz/electricmeterpost/electricMeterQuery";
const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", }, body: new URLSearchParams({ wechatUserId, electricUserUid, }), });
if (!response.ok) { throw new Error(`HTTP ${response.status}`); }
const result = await response.json();
if (result.code !== 0) { throw new Error(result.msg || "查询失败"); }
return result.data;}
const data = await queryElectricity( process.env.WECHAT_USER_ID, process.env.ELECTRIC_USER_UID);
console.log(`剩余:${data.shengyu}`);console.log(`状态:${data.zhuangtai}`);console.log(`累计:${data.leiji}`);这样后续无论是接入网页、Telegram Bot,还是其他自己的程序,都可以直接调用 queryElectricity()。
九、实现低电量提醒
既然已经可以自动获取剩余数据,就可以进一步判断剩余值。
例如低于 20 时输出警告:
const remaining = Number(data.shengyu);
if (remaining < 20) { console.log(`⚠️ 电量不足,当前剩余:${remaining}`);}后续可以结合:
CronNode.jsTelegram Bot邮件Webhook实现每天自动查询一次,并在剩余值较低时发送提醒。
十、总结
整个实现过程实际上可以简化成:
学校电费查询页面 ↓浏览器 Network 抓取请求 ↓找到 electricMeterQuery ↓确认请求方式为 POST ↓提取自己的查询参数 ↓测试移除 H32C6TIi ↓接口仍然正常返回 ↓Node.js fetch 直接查询 ↓解析 JSON ↓定时查询 / 低电量提醒最终并不需要模拟整个浏览器,只需要通过 Node.js 向查询接口发送正常的 POST 表单即可。
对于个人使用来说,这种方式比使用浏览器自动化工具更加轻量,也更方便部署在自己的服务器上。
免责声明
本文内容仅用于个人学习、接口分析以及本人电表信息的自动化查询。
请合理控制查询频率,不要对服务器进行高频请求、批量枚举、扫描或查询未经授权的数据。
学校系统接口及参数可能随时调整,本文仅记录编写时的实际测试结果。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!



