WECHAT_VIDEO_SYNC_WORKS.md 4.3 KB

视频号(weixin_video)同步作品逻辑说明

一、整体流程

作品管理「同步作品」 / 任务队列 sync_works
    → WorkService.syncWorks(userId, accountId?, platform?)
    → 按账号筛选后,对每个账号调用 HeadlessBrowserService.fetchAccountInfo(platform, cookies, ...)
    → 若平台在 supportedPlatforms 内(含 weixin_video),优先用 Python 拉作品
    → fetchWorksViaPython('weixin_video', cookies, onProgress)
    → 请求 Python 服务 POST /works,platform 映射为 'weixin'
    → Python platforms/weixin.py WeixinPublisher.get_works(cookies, page, page_size)
    → 返回 works + total + has_more,Node 据此分页循环
    → 拿到全量 works 后,再调 fetchAccountInfoWithPlaywright 补账号信息(头像、粉丝等)
    → WorkService 用返回的 works 与 DB 做比对:新增/更新/删除本地作品

二、Node 端(HeadlessBrowserService)

  • 平台映射weixin_video → 请求 Python 时用 platform: 'weixin'pythonPlatform = platform === 'weixin_video' ? 'weixin' : platform)。
  • 分页方式:视频号不用游标分页,用页码
    • useCursorPagination = platform === 'xiaohongshu' || platform === 'douyin' → 视频号为 false。
    • 因此 pageParam = pageIndex(0, 1, 2, ...),每次请求带 pagepage_size
  • 每页条数:非小红书/非抖音统一 pageSize = 50
  • 停止条件!result.has_more || pageWorks.length === 0 || newCount === 0 时结束循环。

三、Python 端(platforms/weixin.py)

  • 入口get_works(cookies, page=0, page_size=20),由 run_get_works 调用(app.py 的 /works 路由传 page、page_size)。
  • 当前实现要点
    1. 打开固定页面:https://channels.weixin.qq.com/platform/post/list,等待 div.post-feed-item
    2. self.page.locator('div.post-feed-item') 取当前 DOM 下所有作品项,item_count = await post_items.count()
    3. 只遍历前 min(item_count, page_size) 条,解析封面、标题、时间、播放/点赞/评论/分享/收藏等。
    4. 未使用参数 page:没有根据 page 做滚动、点击「加载更多」或请求下一页接口,每次请求都是同一页 DOM。
    5. 返回值:
      • total = len(works)(当前批数量,非平台总作品数);
      • has_more = item_count > page_size(仅表示当前屏 DOM 条数是否大于 page_size)。

四、存在的问题

  1. 分页未实现

    • Node 会按 has_more 继续请求 page=1, 2, …,但 Python 每次都是同一页、同一批 DOM,第二页起通常会返回重复数据,Node 端 newCount === 0 后停止。
    • 实际效果:只能拿到首屏/首批作品(约几十条),列表若为虚拟滚动,首屏 DOM 条数有限,总数会更少。
  2. work_id 不稳定

    • 使用 work_id = f"weixin_{i}_{hash(title)}_{hash(publish_time)}",同一作品在不同批次或重试中可能 i 不同,且 hash 可能碰撞;若页面有唯一 ID(如接口或 data 属性),应用真实 ID 更稳妥。
  3. total / has_more 含义与 Node 预期不一致

    • Node 用 declaredTotalhas_more 决定是否继续请求;Python 的 total 只是本批条数,has_more 只反映当前屏是否多于 page_size,不能代表「平台是否还有更多作品」。
  4. 调试代码未清理

    • 存在 print("1111111111111111") 等调试输出,以及大段 DOM 打印,建议移除或改为可配置日志。

五、改进方向建议

  1. 实现真实分页
    • 若视频号创作者后台有「加载更多」或滚动加载:在 get_works 里根据 page 做多次滚动或点击,再采集当前屏新增的 div.post-feed-item,并去重。
    • 若有列表接口(如类似抖音 work_list):改为请求接口并解析 cursor/offset 分页,返回 next_page 供 Node 按游标请求(需同步改 Node 对 weixin_video 的分页策略)。
  2. 使用稳定作品 ID
    • 从 DOM 或接口中取作品唯一 ID(若有),作为 work_id,便于去重与和本地库一致对应。
  3. 清理调试并规范日志
    • 去掉无意义 print,DOM 打印改为 debug 级别或环境变量控制。

文档基于当前代码整理,若 weixin.py 或 HeadlessBrowserService 有改动,以实际代码为准。