微信公众号文章 → Obsidian 存档(wechat-obsidian-sync)
将一条或多条微信公众号文章链接抓取为 Obsidian 笔记,产物与用户已装的
wechat-obsync v0.4.10 插件完全同构(同目录、同命名、同 frontmatter、同附件约定),
可无缝共存与互查。
输入
- 必填:1 条或多条
mp.weixin.qq.com链接(短链/s/xxx或长链?__biz=…),
可来自对话文本、剪贴板粘贴或换行/逗号分隔的多行。 - 可选:
--force(覆盖更新库中已存在的同文笔记)。
工作流
Step 1 归一化并收集链接
从用户消息中提取全部 https://mp.weixin.qq.com/… 链接;去重、去空白;
单条即批量为 1。数量较多时告知用户将逐条处理。
Step 2 抓取解析(fetch)
读取 references/parse-notes.md(A/B 类型判定与反爬要点),运行:
cd <skill 目录>/scripts
python3 fetch_wechat.py --outdir /tmp/wechat_sync_out \
--urls "<url1> <url2> …" [--timeout 20 --retry 2]
每条产出 {outdir}/{link_key}.json(url/title/account/author/published_at/
text_md/images/parse_status/error)。对 error 非空的条目记录失败原因
(ERR_VERIFY=风控验证页,建议稍后重试;ERR_DELETED=已删除;ERR_TYPE=非微信链接或结构无法识别)。
Step 3 去重检查
抓取后立即检查结果:
- 若条目 error 非空 → 直接记入"失败"列表,不写库。
- 写库脚本会按 source_url(归一去 #wechat_redirect)与 sync_id 扫描目标文件夹;
命中且未加 --force → 输出"已在: {绝对路径}"并跳过。
Step 4 写库(write)
读取 references/obsync-schema.md(Obsync 精确格式:7 字段 frontmatter、
附件资源/{标题}/img_N.ext、仅空格 %20 编码的 markdown 相对链接),运行:
python3 write_obsidian.py --in /tmp/wechat_sync_out [--force] [--config config.json]
图片原图并发下载(默认 4 线程、Referer=原文 URL、重试 3 次);下载失败的图片序号
进入报告且该篇 parse_status: "img_partial"。
Step 5 汇总交付
向用户输出 Markdown 汇总表,三分类:
- 已保存:vault 内绝对路径 + 图片数(含 parse_status 若非 ok)
- 已存在:命中笔记的绝对路径(未覆盖)
- 失败:URL + 错误码/原因
资源说明
| 文件 | 触发时机 |
|---|---|
scripts/fetch_wechat.py |
Step 2,逐批抓取解析(标准库实现,无第三方依赖) |
scripts/write_obsidian.py |
Step 4,去重+下载图片+写 md(原子写) |
scripts/common.py |
两脚本共享:config/UA/URL 归一/标题清洗/sync_id/解码/图片高清评分 |
references/parse-notes.md |
Step 2 前读取,A/B 判定与风控要点 |
references/obsync-schema.md |
Step 4 前读取,Obsync 精确格式规范 |
config.json |
vault_path/folder/assets_folder/并发/UA 等默认值 |
依赖:Python 3.9+ 标准库(urllib/re/html.parser/hashlib/ZoneInfo),无需 pip 安装。
输出规范
- 笔记文件:
{vault}/微信公众号文章/{published 日期} - {标题}.md - 图片:
{vault}/微信公众号文章/附件资源/{标题}/img_N.<原扩展名> - 每条处理结果以 1 行 JSON 打印;Step 5 用人类可读汇总表交付。
禁止事项
- 不写入
config.json指定 vault 之外的任何目录。 - 不触碰
微信公众号文章/assets/(其它工具的目录)。 - 不伪造 source_url / published_at / 公众号名;抓不到就如实报错。
- 命中微信风控验证页(ERR_VERIFY)立即停止该条,不反复重试轰炸。
- 不把非微信链接当微信文章处理。
- 覆盖更新(--force)仅在用户明确要求时使用。