一键导入
wechat-query
微信公众号文章订阅、查询与推送。依赖内置 `wechat-download-api` 服务缓存公众号文章到 SQLite,优先查库,未命中时再按需调用接口抓取单篇全文。触发条件:用户提到“公众号订阅”“微信公众号文章”“微信文章推送”“公众号更新”等,或由定时推送/巡检任务触发。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
微信公众号文章订阅、查询与推送。依赖内置 `wechat-download-api` 服务缓存公众号文章到 SQLite,优先查库,未命中时再按需调用接口抓取单篇全文。触发条件:用户提到“公众号订阅”“微信公众号文章”“微信文章推送”“公众号更新”等,或由定时推送/巡检任务触发。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | wechat-query |
| description | 微信公众号文章订阅、查询与推送。依赖内置 `wechat-download-api` 服务缓存公众号文章到 SQLite,优先查库,未命中时再按需调用接口抓取单篇全文。触发条件:用户提到“公众号订阅”“微信公众号文章”“微信文章推送”“公众号更新”等,或由定时推送/巡检任务触发。 |
flowchart TD
A[首次使用] --> B[部署并启动 wechat-download-api]
B --> C[健康检查 /api/health]
C --> D[扫码登录<br/>登录有效期按经验约 4 天,可随时重登延长有效期]
D --> E{进入哪条主链路?}
E --> F[模块一: 公众号订阅与文章入库]
E --> G[模块二: 文章查询]
F --> F1[搜索公众号 /api/public/searchbiz]
F1 --> F2[添加订阅 /api/rss/subscribe]
F2 --> F3[手动触发一次轮询 /api/rss/poll]
F3 --> F4[RSS Poller 每小时自动轮询订阅公众号]
F4 --> F5[调用微信后台文章列表接口]
F5 --> F6[默认继续抓取文章全文]
F6 --> F7[写入 SQLite]
F7 --> F8[(表subscriptions)]
F7 --> F9[(表articles)]
G --> G1{缓存库中是否命中?}
G1 -->|命中| G2[直接查询 SQLite 返回结果]
G1 -->|未命中| G3[按需调接口]
G3 --> G4[单篇文章: /api/article/fetch]
G3 --> G5[公众号搜索/文章列表: /api/public/searchbiz /api/public/articles]
flowchart TD
T[定时任务] --> T1[每日 09:00 服务与登录巡检]
T --> T2[每日 18:00 文章推送]
T1 --> T1A[检查 /api/health]
T1A --> T1B[检查 /api/admin/status]
T1B --> T1C[必要时自动拉起服务]
T1C --> T1D[向用户发送巡检结果]
T2 --> T2A[统一预检]
T2A --> T2B[查询最近 24 小时缓存文章]
T2B --> T2C[按 REITs 主题归类整理]
T2C --> T2D[向用户发送推送结果]
<skill-dir>/
├── SKILL.md
├── WINDOWS.md
├── SCHEDULES.md
├── scripts/
│ ├── check_service_and_login.sh
│ └── check_service_and_login.ps1
└── services/
└── wechat-download-api/
├── app.py
├── docker-compose.yml
├── env.example
└── data/
└── rss.db
关键说明:
services/wechat-download-apihttp://localhost:5000services/wechat-download-api/data/rss.dbWINDOWS.md当前 skill 支持两类运行环境:
scripts/check_service_and_login.ps1除“首次部署前的准备动作”外,新的会话默认先执行:
GET /api/healthGET /api/admin/status处理规则:
health 失败:
status.authenticated=false 且从未登录:
status.loginState=invalid:
status.isExpired=true 但未明确失效:
说明:
4 天估算,默认 WECHAT_LOGIN_ESTIMATED_TTL_HOURS=96推荐顺序:
services/wechat-download-api/app.py 是否存在services/wechat-download-api/.env.env 中的镜像源配置是否可用docker compose down 或 docker-compose downdocker compose up -d --buildGET /api/health 正常后,才进入登录二维码获取流程MEDIA: 发送二维码给用户,并明确提醒用户使用公众号管理员微信扫码统一优先使用的登录链路:
POST /api/login/relogin/startGET /api/login/relogin/{request_id}/qrcodeGET /api/login/relogin/{request_id}/status不要把浏览器 Cookie 会话链路作为 agent 主链路:
POST /api/login/session/{sessionid}GET /api/login/getqrcode原因:
常用部署命令:
cd <skill-dir>/services/wechat-download-api
cp env.example .env
docker compose up -d --build
curl -s http://localhost:5000/api/health
Set-Location <skill-dir>\services\wechat-download-api
Copy-Item env.example .env
docker compose up -d --build
Invoke-RestMethod http://localhost:5000/api/health
兼容说明:
docker composedocker-compose,则改用 docker-compose.env 中配置更快的镜像源后再构建镜像源建议:
DEBIAN_MIRROR
mirrors.aliyun.comdeb.debian.orgPIP_INDEX_URL
https://pypi.tuna.tsinghua.edu.cn/simplePIP_EXTRA_INDEX_URL
部署成功判定:
docker compose up -d --build 或 docker-compose up -d --build 返回,不代表服务已经可用docker compose psdocker compose logs --tail 50GET /api/health/api/health 返回正常,才算部署完成首次登录调用顺序:
POST /api/login/relogin/startrequest_idGET /api/login/relogin/{request_id}/qrcodePNG 或 JPEGMEDIA: 发送二维码图片,并明确提醒用户使用公众号管理员微信扫码GET /api/login/relogin/{request_id}/status二维码获取说明:
POST /api/login/relogin/startGET /api/login/relogin/{request_id}/qrcodeGET /api/login/relogin/{request_id}/statusPOST /api/login/session/{sessionid}GET /api/login/getqrcodemessage 工具的 media 参数发送图片/tmp/qrcode.png 这种路径字符串当作普通文本发给用户执行提示与长耗时处理:
docker compose up -d --build 后不要长时间无反馈等待docker compose psdocker compose logs --tail 50GET /api/health处理流程:
GET /api/public/searchbiz?query=公众号名称fakeidPOST /api/rss/subscribePOST /api/rss/poll,但不等待结果10 篇文章,后续将由后台轮询自动持续入库补充说明:
10 篇文章,默认 ARTICLES_PER_POLL=10处理流程:
GET /api/rss/subscriptions处理流程:
DELETE /api/rss/subscribe/{fakeid}说明:
处理流程:
查询方式选择规则:
正文规则:
plain_contentplain_content 为空,再回退 content如果用户提供了微信公众号文章链接(格式:https://mp.weixin.qq.com/s/[加密字符串]),需要获取其内容的处理流程是:
link 在 articles 表中查是否已有缓存POST /api/article/fetch,传入用户给出的公众号文章链接当用户明确要求“重新登录”“重新扫码登录”“重登”时,执行:
POST /api/login/relogin/startrequest_idGET /api/login/relogin/{request_id}/qrcodePNG 或 JPEGMEDIA: 发送二维码,并明确提醒用户使用公众号管理员微信扫码GET /api/login/relogin/{request_id}/status说明:
4 天POST /api/login/relogin/start 返回的 qrcode_path 是服务容器内路径,只适合作为服务内部记录GET /api/login/relogin/{request_id}/qrcode 下载图片,再发送给用户处理流程:
登录状态说明:
lastLoginTime
GET /api/admin/statusestimatedRemainingSeconds
GET /api/admin/statusstatus
GET /api/admin/status文章推送推送规范:
归类要求:
推送内容面向中国 REITs 市场,LLM 在整理新增文章时,必须先按类别归类后再展示。
分类可以参考,也可以根据具体内容自行细分,优先考虑以下类别:
规则:
推送格式示例:
📰 REITs 市场新增文章推送
检查区间:2026-04-10 18:00:00 ~ 2026-04-11 18:00:00
【特定产品新闻】
1. 标题:XX REIT 获上交所受理
公众号:解读REITs
发布时间:2026-04-11 09:32
链接:https://mp.weixin.qq.com/s/xxxxx
摘要:xxx
【项目招标信息】
1. 标题:某商业不动产 REIT 基金管理人项目中标结果公告
公众号:解读REITs
发布时间:2026-04-11 11:20
链接:https://mp.weixin.qq.com/s/zzzzz
摘要:xxx
---
登录状态
- 上次扫码:2026-04-10 08:15:00
- 预计剩余:3天2小时
- 当前状态:登录正常
如需立即重新扫码登录,请回复:需要重登
处理流程:
scripts/check_service_and_login.shscripts/check_service_and_login.ps1巡检脚本输出字段:
ok:整体是否正常service_healthy:服务是否健康service_restarted:本次是否自动拉起并恢复status_checked:是否成功读取登录状态login_state:valid / invalid / unknownauthenticated:当前是否存在登录凭证is_expired:是否已失效或已达到经验过期时间action:建议动作message:脚本给出的说明action 的处理规则:
notify_service_down:通知用户服务异常且自动恢复失败notify_login_invalid:通知用户登录已失效,需要重登notify_not_logged_in:通知用户当前未登录warn_login_expiring:提醒用户登录接近经验过期时间,需要重登none:说明服务和登录均正常建议的巡检消息格式:
公众号服务巡检结果
- 巡检时间:2026-04-10 09:00:00
- 服务状态:正常 / 异常
- 登录状态:正常 / 未登录 / 已失效 / 接近过期
- 自动恢复结果:未触发 / 已恢复 / 恢复失败
- 处理建议:无需处理 / 需要人工处理 / 需要重新登录
如需重新扫码登录,请回复:需要重登
默认原则:
原因:
docker exec 在 Linux、macOS、Windows 下都更稳定建议方式:
docker exec wechat-download-api python - <<'PY'
import sqlite3
conn = sqlite3.connect('/app/data/rss.db')
conn.row_factory = sqlite3.Row
rows = conn.execute("""
SELECT a.link, a.title, a.publish_time, s.nickname
FROM articles a
JOIN subscriptions s ON a.fakeid = s.fakeid
ORDER BY a.publish_time DESC
LIMIT 20
""").fetchall()
for row in rows:
print(dict(row))
PY
数据库路径:
<skill-dir>/services/wechat-download-api/data/rss.db
subscriptions用途:补充公众号名称并提供订阅元信息。
fakeid
TEXTarticles.fakeid 关联nickname
TEXTlast_poll
INTEGERarticles用途:读取文章全文和元信息。
id
INTEGERfakeid
TEXTtitle
TEXTlink
TEXTauthor
TEXTplain_content
TEXTcontent
TEXTplain_content 为空时回退publish_time
INTEGERfetched_at
INTEGERSELECT
a.id,
a.fakeid,
s.nickname,
a.title,
a.link,
a.author,
a.plain_content,
a.content,
a.publish_time,
a.fetched_at
FROM articles a
JOIN subscriptions s ON a.fakeid = s.fakeid
WHERE 1 = 1
AND (:fakeid = '' OR a.fakeid = :fakeid)
AND (:start_ts = 0 OR a.publish_time >= :start_ts)
AND (:end_ts = 0 OR a.publish_time < :end_ts)
AND (:keyword = '' OR a.title LIKE '%' || :keyword || '%')
ORDER BY a.publish_time ASC, a.id ASC;
GET /api/health
GET /api/admin/status
POST /api/login/relogin/start
GET /api/login/relogin/{request_id}/qrcode
request_id
GET /api/login/relogin/{request_id}/status
request_id
GET /api/public/searchbiz
query
GET /api/public/articles
fakeid
begin
0>= 0count
101 <= count <= 100keyword
GET /api/public/articles/search
fakeid
query
begin
0>= 0count
101 <= count <= 100POST /api/article/fetch
url
POST /api/rss/subscribe
fakeid
nickname
""alias
""head_img
""DELETE /api/rss/subscribe/{fakeid}
fakeid
GET /api/rss/subscriptions
POST /api/rss/poll
GET /api/rss/status