物流快递海外仓商家企业微信快递物流群预报单未转单号补录群发提醒Excel批处理
系统演示截图




微信表格自动处理机器人
用户通过个人微信或企业微信向机器人发送 Excel 文件并附上触发语,机器人按表头识别表格类型,
按客户代码归类单号,再把整理好的提醒消息发到对应的企业微信群。
快速开始
venv/Scripts/pip.exe install -r requirements.txt
venv/Scripts/python.exe app.py
启动后打开 http://127.0.0.1:9000 配置参数。首次运行会自动生成 .env。
默认是演练模式(DRY_RUN=true),只写日志不真发消息。确认试算结果正确后,
把 .env 里的 DRY_RUN 改成 false 再重启即可上线。
必须先配的三项
| 配置项 | 说明 |
|---|---|
QIWEI_TOKEN |
开放接口的 X-QIWEI-TOKEN |
QIWEI_GUID |
默认 guid。回调里带 guid 时优先用回调值 |
CALLBACK_SECRET |
回调鉴权密钥,需与消息推送端的 Authorization 头一致 |
把回调地址 http://<你的公网地址>:9000/api/data 配到消息推送后台,请求头Authorization 填 CALLBACK_SECRET 的值。
QIWEI_TOKEN 没配的话,取群昵称、下载文件、发消息全都会失败(接口会返回header:X-QIWEI-TOKEN 不可为空)。启动时如果没配,日志里会有一条 ERROR 提示。
工作流程
- 建群映射 — 任意群消息进来时,若
data/rooms.json里没有该群 ID,就调/room/batchGetRoomDetail取群昵称并追加;已拿到昵称的不再重复请求。存储格式为{"群ID": "群昵称"}。取昵称失败时也会先把群 ID 记下来(值为空串),之后该群再来消息
会自动重试,详见下文。 - 等待配对 — 同一个发送者在
PAIR_WINDOW_SECONDS(默认 300 秒)内既发了
Excel 又发了触发语,才会启动处理。先发文件还是先发触发语都可以。触发语在
「参数配置 → 触发关键词」里改,默认开始处理,处理表格,自动处理,包含匹配
(消息里含有任一关键词即命中)。匹配方式可以在.env里用TRIGGER_MATCH_MODE
改成exact(必须完全相等)。 - 下载文件 — 个微(
msgType=102)走/cloud/wxDownloadAsync,
企微(msgType=15)走/cloud/wxWorkDownloadAsync。两者都是异步的:接口先返回requestId,真实下载地址由后续cmd=20000回调的msgData.cloudUrl带回,
靠requestId对上号。 - 识别与归类 — 按表头判断类型,按客户代码把单号归到一起。
- 匹配群并发送 — 群昵称里包含该客户代码的群即为目标群。
支持的两种表格
一、无尾程面单补录提醒
表头:日期 / 客户代码 / 客户简称 / 客户单号 / 备注1 / 备注2
XM1FH1A015945
XM2252J012802
老板,无尾程面单的订单, 麻烦查一下原因, 不是取消单的话,赶紧补录一下面单,如果补录失败的话,尾程面单导PDF文件以PO号命名发给我们
二、已预报未入库提醒
表头:订单状态 / 客户代码 / ... / 预报日期 / ...(共 28 列)
XM23F7Y026387
这是截止于7.25号已预报未入库的订单目前国内仓库还未收到货物 请您注意一下切勿漏发订单导致无轨迹罚款或者延误哦!Y2872
日期取该客户所有记录中最近的 预报日期,格式为 月.日;结尾附客户代码。
两段话术都可以在 WebUI 里改。第二段支持 {date}(预报日期)和 {code}(客户代码)两个占位符。
WebUI 页面
- 参数配置 — 只放触发关键词、话术模板、表头识别三组,各占一个面板,
保存后写回.env并立即生效(根路径/直接跳到这里) - 群映射 — 只展示自动记录的 群ID→群昵称,不提供手工增改;昵称还没取到的群会单独列出,
可以一键重试 - 表格试算 — 上传或指定本地表格,只解析不发送,用来核对结果
- 群发通知 — 手工发通知:输入一段文字,勾选要发的群,一键发送
其余变量(接口地址、Token、guid、触发匹配方式、配对时间窗、发送行为、行过滤、目录、
日志、清理策略等)都只从 .env 读取,页面上不暴露。需要调整就直接编辑 .env 后重启服务。
这样既避免误操作把密钥、接口地址改坏,也让 WebUI 只专注在日常真正要调的内容上。
上线前建议先用「表格试算」跑一遍,确认客户归类和群匹配都对。
关于是否要过滤已处理的记录(请先确认)
需求文档没有提到按备注筛选,所以默认不过滤,所有行都会处理。但样例1.23-7.23.xlsx 是 1 月 23 日到 7 月 23 日的 6 个月流水,共 70985 行,其中:
备注1:已通知94.4%、已通知代理3.3%、没群,已通知雪纯2.3%备注2:已补录39.5%、已补录-验30.1%、已取消25.8%、已退款1.5%
也就是说约 97% 的记录看起来已经处理完了。按原样全量发送,会把几个月前就已补录或
已取消的单号重新催一遍,其中一个客户有 4315 个单号,会被拆成 44 条消息发到同一个群。
如果确实只想催没处理完的,在 .env 里填上 EXCLUDE_REMARK_KEYWORDS,
例如 已取消,已补录,已退款,已签收,尾程已发货,海外仓已打印标签。填上之后同一个文件的
结果是:1019 个有效单号、258 个客户,单客户最多 120 个单号——量级合理得多。
建议先用「表格试算」对比一下两种配置的结果,再决定上线用哪种。
群发通知
和表格自动处理无关,是给运营手工发通知用的。在输入框里写一段文字,下面会列出所有已记录的群,
勾选后一键发送。带全选/全不选和按群名过滤,方便群多的时候操作。
几个约束:
- 同样受
DRY_RUN约束。演练模式下点发送只记日志,页面会明确告知"实际一条都没发"。 - 只能发给已记录的群。后端会校验群 ID 是否在
data/rooms.json里,不接受任意 ID——
否则这个页面就成了"给任何人发消息"的入口(WebUI 默认还没有密码)。 - 昵称还没取到的群不能勾选,因为那通常意味着接口没配好。
- 真实发送前有二次确认弹窗;每条之间间隔
SEND_INTERVAL_SECONDS,页面会按勾选数量预估耗时。 - 逐群报告结果。全部成功才清空输入框;只要有一个群失败就保留内容和勾选,方便改完重试。
失败的群会单独列出错误原因。
群映射页面看不到群?
群映射完全靠自动记录,收到群消息就写入。如果发了消息却看不到记录,按下面顺序查:
1. 回调有没有进来。 看 logs/app.log 有没有 发现新群 <群ID>。没有的话说明回调
根本没到,检查消息推送后台的回调地址、Authorization 头是否等于 CALLBACK_SECRET
(不匹配会记 回调鉴权失败)。
2. QIWEI_TOKEN 配了没。 这是最常见的原因。没配的话日志里会看到:
获取群昵称失败 room_id=12641087403099: 接口 /room/batchGetRoomDetail 业务失败: code=500 msg=header:X-QIWEI-TOKEN 不可为空
QIWEI_TOKEN 为空,无法调用接口。请在 .env 里填好 QIWEI_TOKEN 后重启服务
这种情况下群 ID 已经记下来了,会出现在页面的「待补昵称的群」里,只是没有昵称。
把 .env 里的 QIWEI_TOKEN 填好重启,然后点页面上的「立即重试获取昵称」即可补齐;
不点也行,该群下次再来消息时会自动重试。
3. 群本身有没有名称。 接口调用成功但 roomName 为空,也会留在「待补昵称」里。
匹配客户靠的是群昵称,所以这种群必须先在微信里给它起个包含客户代码的名字。
失败后不会每条消息都去打接口,冷却时间由 ROOM_NAME_RETRY_SECONDS(默认 300 秒)控制。
客户代码与群的匹配规则
以「群昵称包含客户代码」为准,并做了两点加固:
- 边界校验 — 匹配位置两侧不能紧跟英文字母或数字,避免
Y21误命中Y2138群。
中文不算代码字符,所以Y181客户群能正常命中Y181。 - 精确优先 — 群昵称正好等于客户代码时,优先用这个群。
样例数据里有约 12 个客户(共 1159 个)的 客户代码 是乱码,真代码在 客户简称 里
(如代码 FVFBUQ、简称 Y584)。归类仍按 客户代码,但找群时会回退用简称里的代码再试
一次,避免这些客户被整体跳过。该行为由 FALLBACK_MATCH_BY_ALIAS 控制。
目录结构
app.py Flask 入口:回调接收 + WebUI
config.py 配置管理,读写 .env
processor.py 业务编排:回调分发、配对、处理、下发
excel_processor.py 表头识别、归类、话术生成
matcher.py 客户代码 -> 群 的查找
room_store.py 群映射存储与匹配
notifier.py 群发通知
downloader.py 异步下载 + requestId 配对
cleaner.py 下载目录定时清理
wx_api.py 开放接口封装
logger.py 日志
data/rooms.json 群映射
downloads/ 下载的表格
logs/ 日志
tests/ 测试
下载目录定时清理
下载回来的表格会一直堆在 downloads/,所以内置了定时清理,默认每 24 小时扫一次,
保留 7 天,并且总容量不超过 500 MB。服务启动时也会先扫一次,重启就能回收空间。
| 变量 | 默认值 | 说明 |
|---|---|---|
CLEANUP_ENABLED |
true |
总开关 |
CLEANUP_INTERVAL_HOURS |
24 |
多久扫一次。下限 0.05 小时(3 分钟) |
CLEANUP_KEEP_DAYS |
7 |
保留天数。0 = 每次扫描都清空 |
CLEANUP_MAX_TOTAL_MB |
500 |
总容量上限,超了从最旧的开始删。0 = 不限制 |
两道防线是叠加的:先按天数删过期的,再看总量有没有超上限。所以即使某天来了特别多文件,
占用也不会突破 CLEANUP_MAX_TOTAL_MB。
清理只针对下载目录里的 .xlsx / .xlsm / .xls,其他文件不碰。如果 DOWNLOAD_DIR 被误配成
项目根目录或盘符根目录,清理会直接拒绝执行并记 error 日志,不会误删项目文件。
清理动作会记到 logs/app.log,例如 清理下载目录:删除 2 个文件,释放 4.8 MB(保留 7.0 天),
想确认是否生效就看日志。
把 CLEANUP_KEEP_DAYS 设成 0 时要注意:清理会删掉目录里所有表格,包括刚下载还在处理的那个。
解析是一次性读进内存的,正常不会有影响,但没必要的话不建议设 0。
测试
venv/Scripts/python.exe -m pytest tests -q
注意事项
- WebUI 默认没有密码,任何能访问该端口的人都能改配置、看群映射、手动发消息。
只要不是仅本机访问,就应该设置WEBUI_PASSWORD,并且不要把端口直接暴露到公网。 - 大表格(7 万行)解析约 2 秒,处理在后台线程跑,不阻塞回调响应。
- 下载目录会自动定时清理,默认保留 7 天、总量不超过 500 MB,详见上文。
- 单个客户单号过多时按
MAX_ORDERS_PER_MESSAGE(默认 100)分条发送;拆出的条数超过WARN_MESSAGES_PER_CUSTOMER(默认 10)会记一条警告,方便发现异常量级。 - 每条消息之间间隔
SEND_INTERVAL_SECONDS(默认 1.5 秒),避免触发频率限制。 - 未匹配到群的客户会被跳过并记警告日志,不会误发到别的群。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)