| name | wechat-subscribe-and-ingest |
| description | 当用户说'加订阅'并提供微信文章 URL 时:1) 抓取文章入库 2) 提取 __biz 参数 3) 将公众号添加到 we-mp-rss 订阅列表 4) 重启容器。用户只说 URL 不做加订阅则只执行第 1 步。 |
微信加订阅 + 入库工作流
触发条件
| 用户说 | 动作 |
|---|
| 贴 URL(无关键词) | 只做单篇入库 |
| "加订阅" + 贴 URL | 单篇入库 + 加订阅到 we-mp-rss |
RSS content:encoded 模型 — 理解正文怎么来
extractor 不直接从微信页面抓正文。它读 RSS 的 <content:encoded> 字段,这个字段由 we-mp-rss 的 ContentTaskQueue 在后台填充。
微信 API → we-mp-rss 发现文章 → ContentTaskQueue 抓取 HTML
→ 存入 DB (content_html) → RSS 端点在 content:encoded 中返回
→ extractor 读 RSS → 有 content:encoded → 写入 inbox
新号加了订阅后 RSS 可能返回 0 篇文章或文章有标题但无正文。 这是正常现象——正文补抓受微信反爬限制,需要 best-effort。
文章发现链状态(2026-07-04 已恢复)
we-mp-rss 依赖微信公众平台的 appmsgpublish API 发现新文章。Cookie 过期时该 API 返回 not found:代码:200009,续期后恢复正常。
Cookie 自动续期机制
python3 ~/.hermes/scripts/wechat-cookie-renew.py
恢复验证:Cookie 续期后,fetch_all_article() 从返回 200009 变为正常抓取新文章。7月3日-4日的新文章会自动流入。
中断检测:每天 10am cron wechat-pipeline-monitor 检查 articles 表最新文章时间,超过 48h 无新文章则发邮件到 geekqjg@gmail.com(直连 Gmail SMTP:587,不走代理)。
已知限制
| API | 用途 | 状态 |
|---|
cgi-bin/appmsgpublish | 获取公众号文章列表 | ✅ Cookie 有效时正常工作 |
cgi-bin/searchbiz | 搜索公众号 | ❌ 微信已下线此接口 |
搜索功能已永久失效。添加新公众号只能通过 __biz 提取 → SQLite 直插(见下方"加订阅流程")。
单篇入库(始终执行)
node ~/wiki/scripts/playwright-profile/fetch-with-profile.js "URL" --text
拿到纯文本后用 wiki-pipeline 标准流程:raw/articles/ + entity + index + log + commit。
注意: Playwright Profile 也可能触发微信验证码("环境异常")。此时告知用户该 URL 暂无法自动抓取,需要用户在手机微信上打开文章后复制内容贴给 agent。
加订阅流程(仅限"加订阅"关键词)
1. 提取 __biz
长 URL 格式 mp.weixin.qq.com/s?__biz=XXX → 从 query param 取 __biz 值。
短 URL 格式 mp.weixin.qq.com/s/XXX → 需要用 Playwright 加载页面后读 window.biz。
Playwright 提取方法(需要用户提供 WeChat MP session cookies):
from playwright.async_api import async_playwright
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
ctx = await browser.new_context()
await ctx.add_cookies([
{'name': 'slave_sid', 'value': '...', 'domain': 'mp.weixin.qq.com', 'path': '/'},
{'name': 'slave_user', 'value': 'gh_...', 'domain': 'mp.weixin.qq.com', 'path': '/'},
{'name': 'token', 'value': '...', 'domain': 'mp.weixin.qq.com', 'path': '/'},
])
page = await ctx.new_page()
await page.goto(url, wait_until='domcontentloaded', timeout=15000)
await page.wait_for_timeout(3000)
biz = await page.evaluate('() => window.biz || null')
__biz 值即 faker_id(base64 编码的公众号数字 ID)。
2. 构造 feed_id
import base64
numeric = base64.b64decode(faker_id).decode().strip()
feed_id = f"MP_WXS_{numeric}"
3. 获取公众号名称
document.querySelector('#js_name')?.textContent?.trim()
如果 Playwright Profile 触发验证码无法获取名称,用 "? 占位,后续再补。
4. 写入 we_mp_rss.db(唯一需要写入的 DB)
INSERT OR IGNORE INTO feeds (id, mp_name, mp_cover, mp_intro, status, sync_time, update_time, created_at, updated_at, faker_id)
VALUES ('MP_WXS_{numeric}', '{name}', '', '{intro}', 1, {ts}, {ts}, datetime('now'), datetime('now'), '{biz}')
只写 /Users/jinguo/data/we_mp_rss.db(docker-sqlite 版使用的 DB)。不需要写 db.db(那是 MySQL 版遗留的副本)。
5. 重启容器
docker restart we-mp-rss
6. 验证
sqlite3 /Users/jinguo/data/we_mp_rss.db "SELECT mp_name, status FROM feeds ORDER BY mp_name;"
curl -s "http://localhost:8001/rss/{feed_id}?limit=3" | grep -o '<item>' | wc -l
7. 文章自动发现说明
加订阅后,we-mp-rss 不会主动拉取该号的历史文章。 文章发现依赖 we-mp-rss 后台的定时任务(GATHER.CONTENT_AUTO_INTERVAL=59 分钟)。
appmsgpublish API 需要有效 Cookie(由每日 9am cron wechat-cookie-renew 续期):
- Cookie 有效 → 新文章正常发现,流入 RSS → extractor → inbox
- Cookie 过期 → API 返回
not found:代码:200009,表现为 "Alive but Stale"(Web UI 正常但无新文章)
- 修复:确保 Chrome 运行在
--remote-debugging-port=9222 且 WeChat Profile 已登录,wechat-cookie-renew cron 自动处理
中断监控:每天 10am wechat-pipeline-monitor cron 检查是否有 48h 内新文章,无则发邮件告警。
新订阅号的历史文章只能通过以下方式获取:
- 用户粘贴文章 URL:Playwright Profile → wiki pipeline(实时入库)
- 人工批量补录:攒一批链接后批量处理
正文补抓的限制(必须告知用户)
we-mp-rss 的 ContentTaskQueue 负责补抓正文,但容器内 Playwright 被微信反爬拦截。加了订阅 ≠ 能自动获取正文。 正文入库仍需用户贴 URL 走 Tier 3 路径。
当前反爬墙覆盖三条路径:
- 容器内 Playwright → 验证码
- 本地 Playwright Profile (Tier 3) → "环境异常"(2026-07-02 起)
- 远程浏览器免费版 → 验证码
唯一可靠方式:用户在手机上打开文章 → 复制内容 → 贴给 agent 手动入库。
相关 skill
we-mp-rss-troubleshooting — 容器级故障诊断,含 no_proxy、proxy.enabled、cascade worker 缺失、双 DB 同步等完整故障链。