版本:v1.0(第一阶段) 日期:2026-06-06 状态:待评审
wx-kit 是一个微信百宝箱桌面应用。 第一阶段聚焦"文章下载"这一个模块——把微信公众号文章下载为多种格式并在应用内浏览,同时提供一套 CLI 接口,让 AI 大模型能通过 agent skill 直接调用这些能力。
下载只是第一阶段的需求。产品按"多模块容器"组织,为后续工具(如内容分析、批量改写、素材管理等)留出扩展位,但本阶段不预先搭建任何空模块(YAGNI)。
本产品脱胎于一个技术探索原型(x-downloader),该原型验证了微信文章下载的可行性。产品化阶段做三件事:
- 砍掉代理模式:原型用 AnyProxy 做全局 HTTPS MITM 拦截 PC 微信流量,安装根证书、自动改系统代理,体验脆弱且有还原风险。直接弃用。
- 去掉 Python 边车:原型的爬取逻辑跑在 FastAPI + Playwright + PyInstaller 的独立进程里(PyQt 时代遗留),打包复杂、体积大、有
0.0.0.0监听等问题。本阶段用纯 Node/Electron 重写,单进程单语言。 - 新增 AI 友好的 CLI 接口:核心能力不再只活在 GUI 里,抽到与界面无关的核心层,供 GUI 与 CLI 两个入口共享。
- 用户能基于文章 URL(单个或一次多个)下载文章,自选下载内容。
- 用户能基于公众号批量爬取并下载其历史文章,自选下载内容。
- 用户能在应用内浏览已下载的文章(md / html)。
- AI 大模型能通过 CLI 调用上述下载与爬取能力,获得结构化(JSON)结果。
- ❌ 代理模式 / 流量拦截 / 证书安装(已弃用)。
- ❌ 激活、授权、付费门槛系统(第一阶段开箱即用;后续商业化再议)。
- ❌ 下载以外的"百宝箱"其他工具模块(留架构位,不实现)。
- ❌ 云端同步、多端、账号体系。
- ❌ 评论/留言/阅读数等需要额外接口或风险较高的数据抓取(本阶段只做正文、图片、元数据;列表数据来自公众号后台接口)。
| 用户 | 场景 | 主要入口 |
|---|---|---|
| 个人创作者 / 研究者 | 收藏、归档某篇或某些文章,离线阅读 | GUI · URL 下载 |
| 内容运营 / 分析者 | 批量归档某个公众号的历史文章,做素材库 | GUI · 公众号批量 |
| 知识管理用户 | 在本地统一浏览已归档文章 | GUI · 文章库 |
| AI Agent(大模型) | 通过 skill 自动下载/爬取文章,拿到 md 与元数据做下游处理 | CLI |
AI Agent 是一等公民用户。CLI 的输出契约(JSON + 退出码)按"被程序消费"而非"被人阅读"来设计。
- 输入:一个多行文本框,每行一个微信文章 URL。支持 1 个到多个。
- 格式可选(多选,至少选一项):
- 封面图片(cover)
- Markdown(md)
- HTML(html,图片本地化的自包含单文件)
- PDF(pdf)
- 文章元数据(meta,JSON)
- 行为:所有 URL 进入统一下载队列,逐条处理。
- 进度信息(详见 §8.4):
- 整体进度:已完成 / 总数。
- 每条状态:等待 / 下载中 / 成功 / 失败(+ 失败原因)。
- 单条内的阶段提示:抓取正文 → 下载图片 → 转换格式(md/html/pdf)→ 写入入库,让用户清楚卡在哪一步而非只看到"下载中"。
- 无需登录:URL 下载抓取的是公开文章页,不依赖公众号后台登录。
- 完成后:每篇文章入库,可在文章库浏览。
- 前置:扫码登录后台
- 首次使用批量功能时,引导用户用自己的微信公众号扫码登录
mp.weixin.qq.com。 - 登录在应用内的窗口完成,登录成功后捕获并持久化 session(token + cookie)。
- session 失效时,自动检测并重新引导登录,不让用户面对一句冷冰冰的报错。
- 首次使用批量功能时,引导用户用自己的微信公众号扫码登录
- 搜索公众号:输入公众号名称 → 调后台接口返回候选列表(名称、头像、简介、fakeid)→ 用户选定目标号。
- 选择爬取范围(二选一):
- 按数量:最近 N 篇
- 按日期:起止日期段
- 格式可选:同 F1(cover / md / html / pdf / meta)。
- 队列下载:
- 默认串行 + 随机延迟抓取,宁慢勿封(详见 §9 风控)。
- 进度信息(详见 §8.4):整体进度(已完成 / 总数)、预计剩余耗时、当前正在处理的文章及其阶段;可暂停/取消。
- 单篇失败不中断整体,记录失败项,支持重试失败项。
- 断点续传:已下载的文章跳过,不重复下载(按文章唯一标识去重)。
- 文章库:列出所有已下载文章,按公众号 / 时间分组。
- 每条展示:标题、公众号、发布时间、下载时间、已下载的格式标记。
- 搜索:按文件名 / 标题实时搜索定位文章,可叠加按公众号筛选。
- 内置阅读器:点击文章在应用内直接渲染正文阅读。
- md:渲染为排版良好的阅读视图。
- html:在受控的内嵌视图中展示自包含 HTML。
- 辅助入口:提供"在文件夹中显示""用系统程序打开""导出/拷贝"等操作,方便用户把文章带走。
- 文章管理(删除):
- 删除单篇 / 多选批量删除。
- 删除时同时清理磁盘文件(整篇文章文件夹)与
library.json索引,保证库与磁盘一致。 - 删除为不可逆操作,执行前给确认提示。
CLI 与 GUI 是同一个 Electron 二进制的两种启动模式:检测到命令行子命令即进入无窗口 CLI 模式,执行完打印结果并退出。
输出契约(关键):
- 结构化结果走 stdout,纯 JSON(agent 直接解析)。
- 人类可读的进度/日志走 stderr(不污染 stdout 的 JSON)。
- 退出码:
0成功;非 0 表示失败,错误详情同时写入 stdout 的 JSON({ "ok": false, "error": {...} })。
命令集(第一阶段):
| 命令 | 作用 | 关键参数 |
|---|---|---|
wx-kit login |
打开扫码登录窗口,持久化 session | — |
wx-kit auth-status |
查询登录态是否有效 | --json |
wx-kit search <name> |
搜索公众号,返回候选列表(每项含名称、头像、简介、fakeid),由调用方决定选用哪个 | --json |
wx-kit download |
下载一个或多个文章 URL | --url <u>(可重复)/ --urls-file <f>、--formats cover,md,html,pdf,meta、--out <dir> |
wx-kit crawl <name> |
批量爬取某公众号 | --count N 或 --from YYYY-MM-DD --to YYYY-MM-DD、--formats ...、--out <dir> |
wx-kit library list |
列出已下载文章 | --account <name>、--json |
Agent 调用约定:
crawl/search需要登录态。若无有效 session,命令以结构化错误返回(error.code = "AUTH_REQUIRED"),提示需先执行wx-kit login(交互式扫码,需人工参与一次)。download不需要登录。- 所有耗时命令在 stderr 输出进度,stdout 仅在结束时输出一次最终 JSON。
后续可在 CLI 之上再封装 MCP server,但本阶段先交付 CLI(对 agent skill 最通用、最简单)。
- 默认下载目录、默认勾选格式。
- 批量爬取的抓取节流参数(延迟区间、单次步长)——给高级用户,提供合理默认值。
- 登录态管理(查看登录状态、退出登录/清除 session)。
- 文章库根目录位置(可配置;默认在用户文档目录下,用户可改到任意目录)。
每篇文章下载后,落到独立文件夹(见 §7)。各格式定义:
| 格式 | 文件 | 说明 |
|---|---|---|
| 封面图 | cover.<ext> |
文章封面原图,按原始格式保存 |
| Markdown | content.md |
正文经 HTML→MD 转换(turndown);图片引用指向本地 images/;文首附 frontmatter 元数据 |
| HTML | index.html |
清洗后的自包含单文件:内联样式、图片本地化(指向 images/ 或 base64),断网可读 |
content.pdf |
由清洗后的页面经 Electron printToPDF 生成 |
|
| 元数据 | meta.json |
标题、作者/公众号、发布时间、原文 URL、摘要、封面 URL、下载时间、已生成格式等 |
| 图片 | images/ |
正文图片本地化副本(md/html 选中时生成) |
图片本地化:选中 md 或 html 时,正文图片一律下载到本地并改写引用路径,保证离线可读、可整体拷走。
- 文件系统存储 + 一个 JSON 索引(
library.json),不引入数据库(第一阶段够用,且便于用户直接操作文件)。 - 每篇文章一个自包含文件夹,方便整体拷贝/迁移。
<文章库根目录>/
├─ library.json # 索引:所有文章的元信息 + 路径 + 已下载格式
└─ <公众号名>/
└─ <日期>_<标题>/ # 单篇文章自包含文件夹
├─ index.html # (选中 html 时)
├─ content.md # (选中 md 时)
├─ content.pdf # (选中 pdf 时)
├─ cover.jpg # (选中 cover 时)
├─ images/ # 正文图片本地化
└─ meta.json # 元数据
- 文章库根目录默认在用户文档目录下(如
~/Documents/wx-kit/或同级),且可在设置中配置到任意目录。 - session、设置等应用数据存于 Electron
userData目录,与文章库分离。 - 文件夹/文件命名做非法字符清洗与去重处理。
┌─────────────────────────────────────────────────────────┐
│ 入口层(两种启动模式,同一二进制) │
│ ┌──────────────────┐ ┌──────────────────────┐ │
│ │ GUI 模式 │ │ CLI 模式 │ │
│ │ React 渲染进程 │ │ 命令解析 + JSON 输出 │ │
│ │ ↕ IPC │ │ ↕ 直接调用 │ │
│ └────────┬─────────┘ └──────────┬───────────┘ │
│ └───────────────┬─────────────┘ │
│ ▼ │
│ 核心层 core(UI 无关,被两个入口共享) │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ article- │ mp-crawler │ exporter │ │
│ │ fetcher │ mp-auth │ library │ │
│ │ │ download-queue│ │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ ▼ │
│ 平台能力(Electron 提供):printToPDF · 登录/抓取用的 │
│ BrowserWindow · 文件系统 │
└─────────────────────────────────────────────────────────┘
▼
本地文件系统(§7)
核心层不依赖 React/渲染层;GUI 经 IPC 调它,CLI 经命令行调它。二者同在 Electron 主进程,因此都能复用
printToPDF与 BrowserWindow 登录能力——这是选择"统一 Electron 二进制"的根本原因:一套能力、零额外重型依赖。
| 模块 | 职责 | 依赖 |
|---|---|---|
mp-auth |
用 BrowserWindow 承载扫码登录,捕获 token+cookie,持久化 session,失效检测与重登引导 | Electron BrowserWindow、文件系统 |
mp-crawler |
公众号名→fakeid 搜索;按数量/日期范围翻 appmsg 历史列表;内置节流与失效重登 | mp-auth、HTTP 客户端 |
article-fetcher |
给定文章 URL 抓 HTML,cheerio 清洗正文,下载并本地化图片 | HTTP 客户端、cheerio |
exporter |
把清洗后的文章导出为 cover/md/html/pdf/meta | turndown、Electron printToPDF、文件系统 |
download-queue |
串行队列、随机延迟、进度上报、失败记录与重试、去重 | 上述模块 |
library |
维护 library.json 索引,提供列表 / 按文件名·标题搜索 / 删除(连带清理磁盘文件夹) |
文件系统 |
每个模块单一职责、接口清晰、可独立测试。
- 运行时/打包:Electron + electron-builder(mac dmg/zip、win nsis/zip)
- 渲染层:React + TypeScript + Vite;UI 组件沿用 Ant Design 体系(与原型一致,降低迁移成本)+ Tailwind
- 抓取/解析:axios、cheerio
- 格式转换:turndown(HTML→MD)、Electron
printToPDF(PDF) - CLI:轻量命令解析(如 commander),主进程入口分流
- 无 Python、无独立 chromium 依赖、无数据库
download-queue 是唯一的进度来源,对外发射统一的进度事件,两个入口各自渲染,逻辑不重复:
- 进度事件包含:整体(已完成 / 总数、预计剩余耗时)、当前文章(标题)、当前阶段(抓取 / 下载图片 / 转换 md·html·pdf / 入库)、单条结果(成功 / 失败 + 原因)。
- GUI:经 IPC 把进度事件推到渲染层,实时刷新队列 UI 与进度条。
- CLI:把进度事件格式化写入 stderr(人类可读),stdout 仅在命令结束时输出一次最终 JSON 汇总(含每条成败),保证 agent 解析不被进度污染。
微信公众号后台接口有频率限制,抓取过快会触发风控甚至封号。这是产品稳定性的头号约束。
- 节流优先于并发:批量爬取默认串行,请求间插入随机延迟(默认值给保守区间,可在设置调整)。瓶颈是限速不是带宽,并发无意义。
- 退避:遇到风控信号(接口返回频控错误)时自动退避、降速,并在 UI/CLI 明确告知,而非静默失败或一味重试。
- session 失效:检测到失效立即引导重新登录(GUI 弹登录窗 / CLI 返回
AUTH_REQUIRED),不让用户/agent 面对裸报错。 - 去重续传:已下载文章跳过,崩溃/中断后可继续。
- 反馈引导行动:所有失败态都给"下一步怎么办",不只报告问题。
- 体验:用户触碰到的每一层要丝滑——能自动化的不让用户做(如系统自动管理 session、自动去重);反馈引导行动;渐进式展示(先给核心选项,高级参数收进设置)。
- 跨平台:以 macOS 为主要开发/验证平台(开发者在 mac),构建产物覆盖 macOS 与 Windows。
- 性能:CLI 单次命令在 Electron 运行时下额外启动开销控制在亚秒级;URL 下载单篇在正常网络下数秒内完成(不含限速等待)。
- 可扩展:核心层模块化,为"百宝箱"后续工具预留接入方式,但本阶段不实现空模块。
- 可观测:保留运行日志,便于排查抓取失败。
第一阶段交付以下里程碑(具体拆分在后续实现计划中细化):
- M1 核心层 + URL 下载(CLI 优先):article-fetcher + exporter + download-queue + library +
wx-kit downloadCLI 跑通五种格式。 - M2 GUI 接入 URL 下载 + 文章库 + 内置阅读器:F1、F3。
- M3 登录 + 公众号批量:mp-auth + mp-crawler +
wx-kit login/search/crawl,GUI 批量页。 - M4 打包与跨平台验证:electron-builder 出包,mac/win 验证,CLI 二进制可被 agent skill 调用。
| 项 | 说明 | 处置 |
|---|---|---|
| 微信接口变更 | 后台 appmsg 接口/登录流程可能变动,导致爬取失效 | 抓取逻辑集中在 mp-crawler,便于快速适配;加清晰的失败上报 |
| 风控/封号 | 高频抓取风险 | 默认保守节流 + 退避(§9);文档明确告知用户风险 |
| CLI 登录交互 | 扫码登录天然需要人工一次 | login 命令交互完成;crawl 在无 session 时返回 AUTH_REQUIRED 引导 |
| 文章页结构差异 | 不同文章 HTML 结构不一,清洗可能漏内容 | fetcher 做容错;保留原始 HTML 兜底 |
| PDF 渲染保真 | printToPDF 对复杂排版可能有偏差 | 第一阶段以"可读、完整"为准,不追求像素级还原 |
已决议(原开放问题):
search返回候选列表,由调用方决定选用哪个(不自动取最匹配项)。- 文章库根目录默认在用户文档目录下,且可配置到任意目录。
- GUI 中粘贴多行 URL,勾选任意格式组合,能正确下载并入库。
- GUI 中扫码登录后台后,搜索公众号、按数量或日期范围批量下载成功,失败项可重试。
- 文章库能列出、按文件名/标题搜索、在内置阅读器中打开 md/html。
- 删除文章(单篇/批量)能同时清理磁盘文件夹与索引,且有确认提示。
- 下载过程(URL 与批量)实时展示整体进度、当前文章与所处阶段;CLI 在 stderr 输出进度、stdout 输出最终 JSON。
-
wx-kit download --url ... --formats md,pdf输出合法 JSON,文件正确生成,退出码正确。 -
wx-kit crawl <name> --count 10 --formats md在已登录时成功;未登录时返回AUTH_REQUIRED。 - 无 Python 运行时、无独立 chromium、无数据库依赖;构建产物在 mac 与 win 可运行。
- 批量爬取默认串行节流,触发频控时能退避并给出明确提示。
评审通过后,进入实现计划(implementation plan)阶段。