Files
UpdateDB/README.md
Asukadaisiki 34a6c6d67e feat: 实现微信公众号新闻和视频同步服务
- 使用 draft API 同步文章(适配个人订阅号)
- 使用 material API 同步视频(含详情获取)
- 自动建表(videos)、UPSERT 已有 articles 表
- 同步删除:微信端删除的素材自动从数据库移除
- APScheduler 定时调度,支持 --once 手动触发
- Docker + docker-compose 部署配置

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 13:08:49 +08:00

5.7 KiB
Raw Permalink Blame History

UpdateDB

定时从微信公众号平台获取视频与文章数据,同步到远端 PostgreSQL 数据库。

技术栈

  • Python 3.11
  • httpx (HTTP 客户端)
  • psycopg2-binary (PostgreSQL 驱动)
  • APScheduler (定时调度)
  • Docker 部署

项目结构

UpdateDB/
  main.py           # 入口:启动调度器,支持 --once 手动触发
  config.py          # 加载 .env 配置
  wechat.py          # 微信 API 客户端token 管理、素材获取)
  db.py              # 数据库连接、建表、UPSERT
  sync.py            # 同步编排逻辑
  Dockerfile
  docker-compose.yml
  .env_example       # 环境变量模板
  api_docs/          # 微信 API 文档

数据库变更总结

新建表:videos

程序启动时自动创建(CREATE TABLE IF NOT EXISTS不会影响已有表

CREATE TABLE IF NOT EXISTS videos (
    id          SERIAL PRIMARY KEY,       -- 自增主键
    media_id    VARCHAR(128) UNIQUE,      -- 微信素材 ID唯一约束
    name        TEXT,                     -- 视频文件名(来自列表接口)
    url         TEXT,                     -- 视频播放 URL来自列表接口
    title       TEXT,                     -- 视频标题(来自详情接口)
    description TEXT,                     -- 视频描述(来自详情接口)
    down_url    TEXT,                     -- 视频下载地址(来自详情接口,可能过期)
    wechat_update_time  TIMESTAMP,       -- 微信端更新时间
    created_at  TIMESTAMP DEFAULT NOW(),
    updated_at  TIMESTAMP DEFAULT NOW()
);

后端读取时注意

  • urldown_url 都可能过期失效,建议每次使用前检查可用性,或定期触发同步刷新
  • titledescription 可能为 NULL首次同步时详情接口调用失败
  • url 是播放地址,down_url 是下载地址,两者不同

未修改的表

articles(原有表,未改结构)

程序往这些已有字段写入数据,未新增/修改任何列:

数据库字段 写入内容 微信 API 来源 注意事项
title 文章标题 news_item.title 截断到 200 字符
content 文章 HTML 内容 news_item.content 原始 HTML微信已去除 JS
cover_url 封面图 URL news_item.thumb_url 截断到 500 字符,可能为 NULL
author 作者 news_item.author 截断到 100 字符,可能为 NULL
publish_date 发布日期 item.update_time 转 date 仅日期,不含时分秒
source_url 文章原文链接 news_item.url 截断到 1000 字符,可能为 NULL
wechat_article_id 去重标识 {media_id}_{index} 格式见下方说明

未写入的字段(保持原有值/NULLcategorytags(微信 API 无此数据)

sync_states(原有表,未改结构)

使用已有的 key-value 结构记录同步状态:

key value 示例
wechat_news_sync {"status":"idle","count":42,"last_sync":"2026-04-09T..."}
wechat_video_sync {"status":"idle","count":5,"last_sync":"2026-04-09T..."}

value 是 JSON 字符串,后端可用 json.loads() 解析。

同步删除机制

每次同步完成后,程序会对比微信端和数据库的 media_id

  • 数据库中有、微信端没有的记录 → 自动删除
  • 涉及 articlesvideos 两张表
  • articles 的删除依据:wechat_article_id 中提取的 media_id(按最后一个 _ 分割)

wechat_article_id 格式说明

格式:{media_id}_{article_index}
示例abc123def456_0   (单图文)
      abc123def456_1   (多图文中的第 2 篇)
  • media_id:微信素材 ID一个 media_id 对应一条图文素材
  • article_index:图文内的文章序号(从 0 开始),多图文时会有 0、1、2...
  • 后端查询某篇具体文章:WHERE wechat_article_id = '{media_id}_{idx}'
  • 后端查询某条图文素材的所有文章:WHERE wechat_article_id LIKE '{media_id}_%'

数据写入策略

  • articlesSELECT 检查 wechat_article_id 是否存在 → 存在则 UPDATE,不存在则 INSERT
  • videosINSERT ... ON CONFLICT (media_id) DO UPDATE,仅在 wechat_update_time 更新时覆盖
  • sync_statesINSERT ... ON CONFLICT (key) DO UPDATE,每次同步更新状态

快速开始

本地开发

  1. 安装依赖:
pip install -e .
  1. 复制配置文件并填写:
cp .env_example .env
# 编辑 .env填入 app_secret 和数据库信息
  1. 运行:
# 启动定时同步(默认每 48 小时)
python main.py

# 只运行一次
python main.py --once

Docker 部署

  1. 在 VPS 上克隆仓库,创建 .env 文件:
cp .env_example .env
# 编辑 .env
  1. 构建并启动:
docker compose up -d --build
  1. 查看日志:
docker compose logs -f

环境变量

变量 必填 说明
app_id 微信公众号 AppID
app_secret 微信公众号 AppSecret
db_host PostgreSQL 主机
db_port PostgreSQL 端口
db_name 数据库名
db_user 数据库用户
db_pw 数据库密码
sync_interval_hours 同步间隔(小时),默认 48

同步逻辑

  1. 调用微信稳定版 Token 接口获取 access_token自动缓存和刷新
  2. 分页获取所有 news图文和 video视频素材
  3. 对视频素材,额外调用详情接口获取下载地址
  4. 使用 UPSERT 写入数据库INSERT ON CONFLICT DO UPDATE
  5. news 和 video 独立同步,一个失败不影响另一个