Skip to content

聊天消息采集技术方案

1. 目标

面向第三方服务商聊天存档页面,建设一套可落地的聊天消息采集能力,用于完成以下目标:

  • 采集员工列表、会话列表、聊天消息索引
  • 解密并还原文本、表情、图片等真实消息内容
  • 支持大消息量场景下的全量补采与日常增量同步
  • 支持登录失效后的人工扫码恢复与断点续跑
  • 将采集结果沉淀为结构化数据,供后续分析、客服质检、运营回访等场景使用

本方案聚焦技术设计与实现路径,不包含当前阶段的正式编码交付。

2. 现状判断

2.1 页面性质

当前聊天页面属于第三方服务商页面,不是我方自有页面源码,不能通过直接修改前端代码解决采集问题。

页面本身更像一个承载壳,真实消息数据并不完全存在于首屏 HTML,而是依赖以下两层接口链路:

  1. 第三方服务商接口返回消息索引
  2. 企业微信开放接口返回解密后的真实消息内容

2.2 已确认接口

2.2.1 消息索引接口

域名:

  • https://weibanzhushou.com

接口:

  • /api/chat/staff_session/msg

示例参数:

  • limit=40
  • session_ext_id=wmt_7EDAAABnmm-ZJnpwSB4D805vR1iw
  • staff_ext_id=MiaoDaYe
  • msg_source=oa

已确认可返回字段:

  • id
  • ext_id
  • msg_type
  • direction
  • msgtime
  • from_id
  • from_name
  • to_id
  • session_id
  • session_type
  • staff_ext_id
  • secret_key

该接口的特点是:

  • 返回的是消息索引和元信息
  • text_contentcontent 可能为空
  • 真正明文内容不能完全依赖本接口

2.2.2 消息解密接口

域名:

  • https://open.work.weixin.qq.com

接口:

  • /chatdata/getchatdata

请求体结构:

  • items
  • sid
  • reqid

其中每条 item 至少包含:

  • msgid
  • encrypt_info.secret_key

已确认可返回字段:

  • msgid
  • msgtype
  • text.content
  • emotion.url

该接口的特点是:

  • 支持批量解密
  • 需要有效登录态
  • sid 是关键鉴权参数
  • reqid 更像请求跟踪 ID,可由客户端生成

2.3 当前关键结论

基于现有抓包结果,可以得出以下结论:

  1. 聊天消息采集应以接口采集为主,不建议以 DOM 抓取为主
  2. 消息索引与消息明文必须拆成两段式采集
  3. 已打开过的聊天页面可能不会再次触发解密请求,因此不能依赖页面行为被动抓取 getchatdata
  4. 大消息量场景下,若每次全量重爬,将产生明显延迟和限流风险
  5. 登录态失效后需要人工扫码恢复,因此整体系统应设计为“半自动恢复”模式

3. 总体方案

3.1 方案原则

  • 优先采接口,不依赖复杂页面结构
  • 索引先落库,明文异步补齐
  • 支持断点续跑,不做重复全量扫描
  • 登录失效后自动检测,人工扫码恢复
  • 所有采集过程尽量可观测、可重试、可恢复

3.2 总体架构

建议整体拆成 5 个模块:

  1. 登录态管理模块
  2. 员工与会话枚举模块
  3. 消息索引采集模块
  4. 消息解密模块
  5. 数据存储与调度模块

数据链路如下:

  1. 浏览器登录第三方后台并保持登录态
  2. 采集员工列表
  3. 采集员工下的客户、同事、群聊会话列表
  4. 对每个会话调用 msg 接口采集消息索引
  5. ext_id + secret_key 批量送入 getchatdata
  6. 合并消息索引与明文解密结果
  7. 落库并更新同步游标

4. 数据采集流程设计

4.1 员工列表采集

员工列表来源可分为两类:

  1. 页面列表接口
  2. 当前页面 DOM

建议优先级如下:

  1. 优先定位员工列表接口
  2. 若短期内无法稳定定位,则先解析左侧 DOM 作为过渡方案

建议采集字段:

  • staff_ext_id
  • staff_name
  • staff_alias
  • avatar
  • status
  • corp_id
  • is_active
  • raw_json

4.2 会话列表采集

会话列表指每个员工下的:

  • 客户
  • 同事
  • 群聊

当前已确认会话列表接口:

  • /api/chat/session/staff/list

示例参数:

  • staff_ext_id=DaBai
  • offset=0
  • limit=50
  • session_type=room
  • session_type=other_staff
  • session_type=ext_user

对于同事会话,当前已确认还会附带参数:

  • use_union_mode=1

当前已确认该接口返回:

  • session_list
  • total_count

建议将该接口定义为员工维度会话枚举主接口,不同会话类型通过 session_type 区分。

当前已确认的会话类型至少包括:

  • room:群聊会话
  • other_staff:同事会话
  • ext_user:外部客户会话

建议优先通过接口拿取以下字段:

  • session_ext_id
  • session_name
  • session_type
  • last_msg
  • last_msg_time
  • staff_ext_id
  • avatar
  • remark_name
  • remark
  • type
  • group_type
  • chat_status
  • last_msg_thumb
  • room_user_list
  • agree_msgaudit
  • agree_status_text
  • raw_json

该接口建议采用分页枚举:

  1. offset=0 开始
  2. 固定 limit
  3. 每次处理 session_list
  4. offset += limit
  5. 直到 offset >= total_count

字段映射建议如下:

  • ext_id 映射为 session_ext_id
  • name 映射为 session_name
  • session_type 直接落库
  • group_type 区分 staff_groupexternal_group
  • chat_status 作为会话活跃状态
  • last_msg_thumb 作为最近一条消息预览
  • last_msg_time 作为最近活跃时间
  • room_user_list 保留原始 JSON 字符串,并按需解析为成员 ID 列表

其中 room_user_list 建议重点保留,原因如下:

  • 可用于还原群成员范围
  • 可区分内部员工与外部客户
  • 外部客户成员通常表现为 wmt_*
  • 内部员工成员通常表现为员工 staff_ext_id

针对 session_type=other_staff,当前已确认以下特征:

  • session_ext_id 可直接使用同事的 ext_id
  • room_user_list = null
  • staff_ext_id 为当前员工标识
  • agree_msgaudit 可能为 truenull
  • 列表层 session_type = other_staff
  • 消息层 session_type 可能表现为 staff

因此实现层建议:

  • 保留列表层原始 session_type
  • 消息层允许出现 staff
  • 不强行要求列表层与消息层类型命名完全一致
  • 增加一层内部标准化类型映射,例如统一映射为 internal_staff

如其他类型会话接口短期未定位到,可先通过中间栏 DOM 过渡采集,但最终仍建议回归接口方式。

4.3 消息索引采集

对每个会话调用:

  • /api/chat/staff_session/msg

已确认该接口支持分页参数:

  • max_id

当前可将该接口定义为“按消息主键倒序翻页”的历史索引接口,推荐规则如下:

  1. 首次请求不带 max_id
  2. 取当前页最后一条消息的 id
  3. 下一页请求带 max_id=最后一条.id
  4. 持续翻页直到返回空列表或返回条数小于 limit

建议采集并落库字段:

  • msg_row_id
  • msg_ext_id
  • session_ext_id
  • room_ext_id
  • staff_ext_id
  • message_type
  • direction
  • msg_type
  • msgtime
  • from_id
  • from_name
  • to_id
  • secret_key
  • raw_index_json

此阶段目标不是拿完整内容,而是快速把消息索引稳定落地。

4.4 消息解密采集

对消息索引中的未解密消息,按批量方式调用:

  • /chatdata/getchatdata

请求体核心字段:

  • items[].msgid = ext_id
  • items[].encrypt_info.secret_key = secret_key
  • sid
  • reqid

建议将解密结果落到单独字段:

  • decoded_msgtype
  • text_content
  • emotion_url
  • image_url
  • file_url
  • voice_result
  • mixed_items_json
  • revoke_item_json
  • raw_decoded_json

4.5 索引与解密合并

最终对外使用的消息记录建议为一条统一消息表记录,合并以下内容:

  • 索引层元数据
  • 解密层真实消息体
  • 同步状态
  • 失败重试信息

5. 登录态管理设计

5.1 登录态组成

当前方案至少涉及两套登录态:

  1. 第三方服务商站点登录态
  2. 企业微信开放消息页登录态

其中关键参数包括:

  • 第三方站点 session_id
  • 第三方站点相关 Cookie
  • 企业微信开放页会话凭证
    • 请求头字段:open-msg-user-sid
    • 请求体字段:sid
  • 企业微信 wwopen.open.sid

5.2 登录失效处理

登录失效是本方案中的高频问题,必须作为系统级能力设计。

建议定义以下状态:

  1. RUNNING
  2. SESSION_EXPIRED
  3. WAIT_RELOGIN
  4. RESUME

处理流程:

  1. 采集任务调用接口
  2. 若判定登录失效,则立即停止采集
  3. 发送告警通知人工扫码
  4. 人工恢复登录后,系统自动从断点继续

6. 大消息量与性能设计

6.1 性能瓶颈

消息量大时,主要瓶颈来自以下几类:

  1. 员工枚举耗时
  2. 会话枚举耗时
  3. 消息索引分页耗时
  4. 消息解密二次请求耗时
  5. 限流与失败重试

6.2 正确的性能策略

建议拆成两个独立队列:

  1. 索引采集队列
  2. 明文解密队列

索引先入库,明文异步补齐,避免全流程串行阻塞。

6.3 同步模式设计

建议支持两类同步模式:

6.3.1 全量历史补采

适用于首次接入:

  • 允许耗时较长
  • 支持断点续跑
  • 分员工、分会话逐步完成

6.3.2 日常增量同步

适用于日常运行:

  • 只抓新消息
  • 优先最近 1 天、3 天、7 天
  • 延迟目标设为分钟级到小时级

7. 数据库设计建议

7.1 建议核心表

  • chat_staff
  • chat_session
  • chat_message_index
  • chat_message_content
  • chat_sync_cursor

7.2 设计原则

  • 索引表和明文表分离
  • 会话和消息保留原始字段,方便后续排障
  • 单独维护同步游标,支持断点续跑
  • 对高敏感字段保留最小必要集

8. 调度与运行设计

8.1 运行形态建议

建议采用“常驻浏览器 + 定时采集 Worker”的方式:

  1. 浏览器进程负责保留登录态
  2. 采集 Worker 负责调用接口和落库

8.2 推荐运行环境

  • 固定一台 Windows 机器
  • 固定浏览器 Profile
  • 固定网络环境
  • 定时任务驱动增量同步

8.3 调度策略

建议调度拆为:

  1. 每日或每小时同步员工与会话
  2. 每 5 到 15 分钟执行消息增量同步
  3. 凌晨低峰期执行历史补采任务
  4. 登录失效时暂停任务并告警

9. 风险与边界

9.1 已知风险

  • 第三方页面结构和接口可能调整
  • 登录态会失效,无法完全无人值守
  • 企业微信开放接口可能限流
  • 历史分页机制尚需继续确认
  • 某些消息类型可能存在额外解析复杂度

9.2 当前边界

本方案适合:

  • 半自动采集
  • 可接受人工扫码恢复
  • 以增量同步为主要目标

本方案不承诺:

  • 永久稳定免扫码
  • 零延迟全量同步
  • 在第三方接口完全变更后无需维护

10. 最终建议

综合当前信息,推荐的最终路线如下:

  1. 以接口采集替代页面爬取
  2. 采用“消息索引 + 明文解密”双阶段方案
  3. 用固定浏览器登录态解决 sid 获取与扫码恢复问题
  4. 采用“首次全量、后续增量”的同步策略
  5. 将系统目标设为“低频人工介入 + 自动断点恢复”

内部使用文档,请按项目和专题归档维护。