2a612d7fd60261d486a23efb2553753a7f191635
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()
);
后端读取时注意:
url和down_url都可能过期失效,建议每次使用前检查可用性,或定期触发同步刷新title和description可能为 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} |
格式见下方说明 |
未写入的字段(保持原有值/NULL):category、tags(微信 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:
- 数据库中有、微信端没有的记录 → 自动删除
- 涉及
articles和videos两张表 - 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}_%'
数据写入策略
- articles:
SELECT检查wechat_article_id是否存在 → 存在则UPDATE,不存在则INSERT - videos:
INSERT ... ON CONFLICT (media_id) DO UPDATE,仅在wechat_update_time更新时覆盖 - sync_states:
INSERT ... ON CONFLICT (key) DO UPDATE,每次同步更新状态
快速开始
本地开发
- 安装依赖:
pip install -e .
- 复制配置文件并填写:
cp .env_example .env
# 编辑 .env,填入 app_secret 和数据库信息
- 运行:
# 启动定时同步(默认每 48 小时)
python main.py
# 只运行一次
python main.py --once
Docker 部署
- 在 VPS 上克隆仓库,创建
.env文件:
cp .env_example .env
# 编辑 .env
- 构建并启动:
docker compose up -d --build
- 查看日志:
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 |
同步逻辑
- 调用微信稳定版 Token 接口获取 access_token(自动缓存和刷新)
- 分页获取所有 news(图文)和 video(视频)素材
- 对视频素材,额外调用详情接口获取下载地址
- 使用 UPSERT 写入数据库(INSERT ON CONFLICT DO UPDATE)
- news 和 video 独立同步,一个失败不影响另一个
Description
Languages
Python
99.2%
Dockerfile
0.8%