微信公众号获取
> 微信公众号获取,给个公众号名就行;也可以直接给一条链接(该号任意一篇图文,或合集)。
开场提示语(固定)
技能被唤起时,第一句只输出下面这行,不要输出技能名、参数说明或命令:
微信公众号获取,给我公众号名就行;也可以直接给一条链接(该号任意一篇图文,或合集)。
用户只给了名字(如「帮我下尚音爱乐」)时:直接跑 find "尚音爱乐"。
不要先索要链接、不要让用户去手工复制——搜一下比让他翻微信快得多。跑完只有两种结果:
- 搜到了 → 把清单摆出来,问下哪些、下几条。若这些文章属于某个合集,
会顺带把合集整册列全(这一步免登录),清单里会分成两栏。 - 没搜到 → 如实说这个名字没被收录,再请他给一条链接:
这个名字没被搜到(搜狗只收录了一部分公众号的文章)。 给我一条链接更快: · 该号任意一篇文章 → 右上角「…」→ 复制链接 · 或该号的合集 → 右上角「…」→ 复制链接 一条就够,剩下我来找。
清单出来后一律先「名称 + 数量」摆出来,再问用户下哪些、下几条,
不要未经确认就整号批量下载。
用途
把微信公众号的内容抓成可离线阅读、可长期保存的本地归档:正文转 Markdown 与独立 HTML,
图片/语音/视频下载到本地目录,合集(专辑)整份批量归档并生成索引清单。
能力边界:
- 支持:按公众号名直接搜、由一篇链接带出该号全部合集与历史图文(有登录态时为全量)、
合集名称与条数统计、图文正文与排版、图片、微信语音(mpvoice)、音频/音乐、图文内嵌视频、
整份合集/专辑、批量链接清单、按类型指定篇数下载,以及
「先查清单 → 用户选内容 → 指定条数 → 下载」。 - 不绕过:付费内容、需关注才能看的私密内容、已删除/违规下架的页面、纯视频号(channels)直播间。
- 视频直链随文章页下发(
mp_video_trans_info),带 4 档清晰度,只需Referer
就能下(见「第 0 步」),所以下视频不需要 Cookie。只有「列全号合集 / 全量历史」
才要登录态(见「第 0.5 步」),且默认自动读取。
极少数视频是视频号 / 外链(v.qq.com、channels),这类只能保留链接,会如实说明。
输入:三种都行
| 用户给的是 | 能查到 | 能下到 | 可靠性 |
|---|---|---|---|
| 公众号名称(如「出师记」) | __biz、正式昵称、被收录的图文清单;文章属于合集时免登录把合集整册列全 |
搜到的那些(是该号的一部分,不是全部) | 覆盖因号而异:实测头部号 38~44 篇,小众号只有个位数甚至 0 篇 |
图文链接 /s/xxxx(该号任意一篇即可) |
文章标题、公众号、__biz、所属合集名称与条数;有登录态时还能列出该号全部合集 + 全部历史图文 |
这一篇(含图片/音频/视频);连同该号全量(需登录态) | 最可靠 |
合集链接 appmsgalbum?...&album_id=... |
合集名、条目总数、图文/视频/音频各多少、逐条标题 | 整份合集,可按类型与条数截取 | 最可靠 |
复制方式(需要告诉用户时就这两句):微信里打开文章或合集 → 右上角「…」→ 复制链接。
收费:按次付费(付费版必读)
本包按次收费:一次抓取调用对应一次付费。付费三步走完,再执行 wx_mp.py。
node scripts/wx_pay.mjs probe --query "出师记" --state-dir .state # 1. 拿 402 账单
node scripts/wx_pay.mjs pay --state-dir .state --session-id "$SESSION_ID" --query "出师记"
node scripts/wx_pay.mjs complete --state-dir .state --trade-no "$TRADE_NO" --query "出师记"
python scripts/wx_mp.py find "出师记" -o ./archive # 4. 真正的抓取
probe未付款时网关返回 HTTP 402 +Payment-Needed账单,账单落在.state/payment-needed.txt(权限 600)。pay调官方alipay-bot 402-buyer-pay拉起收银,必须由用户本人扫码或免密确认;脚本不接触任何密钥。complete调402-query验付,回带的 Payment-Proof 凭证以X-Payment-Proof头重放给网关,
换取一次性使用许可(.state/grant.json),再发履约回执 ack(402-fulfillment-confirm);重复执行幂等,不会重复扣费。- 全程不向用户展示支付链接、二维码原文或交易号,只说「正在拉起收银 / 支付已完成」。
- 依赖官方支付 CLI:
npx -y @alipay/agent-payment@latest install(提供alipay-bot)。 - 网关地址用
PAY_RESOURCE_URL指定;默认为本地联调地址,上架前必须改成你的公网 HTTPS。 - 联调期服务端可用
AIPAY_MODE=mock(不验真款),上线前必须切real。
数据来源优先级(重要)
按可靠性从上到下选:
| 顺序 | 来源 | 能力 | 前提 |
|---|---|---|---|
| ① | 一篇链接 + 登录态:profile_ext?action=getmsg(历史消息)、getalbum_list(全部合集) |
该号全量图文列表 + 全部合集名称与条数,稳定不限流 | 登录态(wxuin+key+pass_ticket);用 cookie --auto 自动读取 |
| ①.5 | 视频直链:文章页内 mp_video_trans_info |
4 档清晰度 mp4,免登录 | 无(只需 Referer) |
| ② | 链接直读:合集页 / 图文页 | 合集全量;单篇正文与媒体。不依赖任何搜索 | 用户给链接 |
| ③ | 公众号名 → 搜狗搜索:wx_search(PC + 移动双入口)→ /link 还原 → 文章页取 __biz |
该号被收录的图文;文章有合集时能免登录读全整册;拿到 __biz 后可升级成 ① |
无 Cookie;需真实浏览器 UA + 3.5s 节流 |
| ④ | 搜狗 type=1(按名字搜公众号主页) |
已被搜狗关闭:连「人民日报」「央视新闻」都返回「暂无相关的官方认证订阅号」 | 不可用,别再试 |
- 微信自身没有免登录的「按账号枚举内容」接口(
getalbum_list返回 no session、
profile_ext落到验证页),所以名称入口只能走外部搜索。 - ③ 是能用的,但不是全量:搜到多少是该号被收录多少,务必如实说明,
别让用户以为这就是全部篇数。 - 用户给了名字、③ 又搜不到时,别重复试第三次,直接索要一条链接。
第 0 步:视频直链就在文章页里(不需要登录态)
公众号视频的 mp4 直链是随文章页一起下发的,藏在 mp_video_trans_info 数组里 ——
一个视频通常 4 档清晰度,每档都带签名 URL、filesize、宽高、时长:
10002 1280x720 超清 28.6 MB
10102 1080x606 超清 19.0 MB
10004 854x480 流畅 10.6 MB
10104 480x270 流畅 6.1 MB
不走任何接口,也不需要 Cookie。 实测下载只要一条 Referer:
GET http://mpvideo.qpic.cn/xxx.f10002.mp4?dis_k=...&auth_info=...
Referer: https://mp.weixin.qq.com/ → 200 video/mp4
实收 6,416,310 字节,与页面声明完全一致
要点(都是实测踩出来的):
| 事项 | 结论 |
|---|---|
| Referer | 必须带 https://mp.weixin.qq.com/,缺了就是 403 |
| User-Agent | 无所谓,PC / 手机 / 不带都能下 |
| http 与 https | 都可能受理,失败会自动换协议重试 |
| 断点续传 | CDN 支持 Range,脚本已用 |
| 时效 | dis_t / auth_info 带过期时间,抓到就下,别攒着 |
| 页面残缺 | 限流时回骨架页(变量在但没有直链),脚本会隔 2.5 秒重抓一次 |
清晰度用 --quality 选:
python wx_mp.py album "<合集链接>" --quality best # 默认:体积最大那档(通常 720P 超清)
python wx_mp.py album "<合集链接>" --quality 流畅 # 挑标着「流畅」的档
python wx_mp.py album "<合集链接>" --quality 10004 # 直接指定代号
第 0.5 步:什么时候才需要登录态
只有一件事需要:列该号的全量合集 / 全量历史图文(profile_ext、getalbum_list
未登录返回 {"ret":-3,"errmsg":"no session"})。视频不需要,下载不需要。
- 只想把眼前这条链接里的东西存下来 → 什么都不用配,直接下
- 想「给一篇文章,就列出该号全部合集与全部历史图文」→ 跑一次
cookie --auto
python wx_mp.py cookie # 无参即自动找一次
python wx_mp.py cookie --auto # 同上
自动读取的三处来源(wx_cookie.auto_extract):
| 来源 | 位置 | 说明 |
|---|---|---|
| 微信浏览记录 | %APPDATA%\Tencent\xwechat\radium\web\profiles\*\History |
微信打开文章时 URL 自带 key/pass_ticket,History 一定落盘,命中率最高 |
| 微信 Cookie 库 | 同目录 */Network/Cookies |
v10/v11 + AES-256-GCM,密钥由 DPAPI 保护;明文前 32 字节是 SHA256(host_key),需剥掉 |
| 其它浏览器 | 企业微信 / Edge / Chrome / QQ / 360 | 同一套解密逻辑 |
读到的候选会逐个拿真实视频打接口实测,只保存真能用的那一条,写进
~/.wechat-mp-cookie.txt(之后所有命令自动复用,不必再传 --cookie)。
读取范围是收敛的:只取 qq.com / weixin 域下 wxuin/key/pass_ticket 等几个字段,
其它站 Cookie 不落盘、不外传。
读不到时只差一步,仍然不用复制任何东西:
1) 在微信 PC 端打开该公众号任意一篇文章(打开就行,不必是视频)
2) 关掉那篇窗口,回来重跑:python wx_mp.py cookie --auto
(必须是电脑上的微信,手机上打开不在本机留痕。Cookie 库常被 WeChatAppEx.exe 独占,
报 WinError 32 时会单独列出来,这时先退出微信再跑一次。)
兜底的手工方式(前两条都不行才用):
python wx_mp.py cookie --paste # 从剪贴板读(Cookie 很长,手粘容易漏字符)
python wx_mp.py cookie --set "wxuin=...; key=...; pass_ticket=..."
python wx_mp.py cookie --check # 看是否还有效
python wx_mp.py cookie --clear # 删掉
粘贴格式不用管:Cookie: 前缀、换行、首尾引号、curl -H 'Cookie: ...' 都会被自动清理。
另外 find / article / album 传进来的链接,会自动从 query 里捡 key/pass_ticket/uin
(显式给的值优先,链接只做补充)。
> 常见误区:扫码登录 mp.weixin.qq.com 拿到的是公众号后台票据(bizuin/slave_sid),
> 不是读者登录态,is_login 依然是 0。登录态只存在于微信客户端。
登录态等同账号凭证:只存本机(~/.wechat-mp-cookie.txt,权限 600),不要贴到公开场合;
在微信里「退出登录」即可让它失效。
环境
脚本除 requests 外无第三方依赖(标准库解析 HTML)。Windows 自带 Python 一般没有 requests,
优先使用 WorkBuddy 托管的 Python 绝对路径;脚本内部已切 UTF-8,不需要先改控制台编码。
在 scripts/ 目录下执行,或用绝对路径调用 wx_mp.py。
路径含中文、空格或 & 时必须整体加双引号——合集链接本身带 &,不加引号会被 shell 截断。
六个入口
1. 查找并下载(find,默认入口)
固定四步,不要跳步,也不要替用户决定下什么。
> 输入三种都收:公众号名、图文链接、合集链接。用户只给名字时直接搜,别先索要链接。
第 1 步 输入:公众号名,或图文地址 / 合集地址(**一条即可**)
第 2 步 列表:打印合集名、图文篇名、条数,每条带编号
第 3 步 确认:问用户「下全部,还是指定的几篇」
第 4 步 下载整理:落到 <out>/<公众号>/<合集名>/,并生成索引
第 1、2 步(只查):
python wx_mp.py find "出师记" -o ./archive # 只给名字,直接搜
python wx_mp.py find "https://mp.weixin.qq.com/s/xxxx" -o ./archive # 一篇图文 → 带出全号
python wx_mp.py find "https://mp.weixin.qq.com/mp/appmsgalbum?__biz=..&album_id=.." -o ./archive
python wx_mp.py find "<article_url>" "<album_url>" -o ./archive # 多个链接合并成一份清单
按名字搜时的可调参数(都可不填):
--pages 4 # PC 与移动端各翻几页,默认 4;翻得越多搜到的篇数越多,约 3.5s/页
--probe 2 # 探测前几篇来确认该号的 __biz 与正式昵称,默认 2
按名称搜的清单长这样。小号多半只有散篇,出师记 的完整实测输出如下:
──────────────────────────────────────────────────────────────
公众号:出师记(MzI2NjQxNzMxNg==)
发现 1 组内容,共 1 条(图文 1)
──────────────────────────────────────────────────────────────
编号 合集 / 来源 类型 条目 图文 视频 音频
1 散篇(未归属合集) 散篇 1 1 0 0
[1] 散篇(未归属合集)(1 条)
1.1 “惠考加油站”更名为“出师记” 图文 | 2022-04-28
· 「出师记」按名称搜索:搜到 1 篇(这是搜狗收录到的部分,不是该号全部)。
若该号的图文落在合集里,清单会多出「合集」这一组,并把那张合集整册列全(这一步免登录)。
格式示意(〈〉 是占位,不是实测数字):
编号 合集 / 来源 类型 条目 图文 视频 音频
1 〈合集名〉 图文合集 〈A〉 〈A〉 0 0
2 散篇(未归属合集) 散篇 〈B〉 〈B〉 0 0
[1] 〈合集名〉(〈A〉 条)
1.1 〈合集内第 1 篇标题〉 图文 | 〈日期〉
…
[2] 散篇(未归属合集)(〈B〉 条)
2.1 〈散篇第 1 篇标题〉 图文 | 〈日期〉
…
出现合集时给用户报数必须把两类分开说:合集里的是完整的(〈A〉 条),散篇只是搜到的(〈B〉 条)。
只要搜到合集中的任意一篇,就能顺着它把合集读全,所以小号也可能一下带出几十条。
第 3、4 步(交互式:清单 → 问 → 下):
python wx_mp.py find "出师记" --download
问法固定为:
【第 3 步】要下载哪些内容?(回车 = 全部 N 条)
1 只下第 1 组全部,可写 1,2
1.3 只下第 1 组的第 3 篇;也可写 1.3,1.5 或区间 1.3-1.6
t 只下图文 v 只下视频 m 只下音频/音乐
all 全部 q 退出
>
下载多少条?(回车 = 全部 N 条,或输入数字如 5)
非交互(脚本/自动化)用 --select 表达同一件事,给了 --select/--count 就视为已确认、直接下载:
python wx_mp.py find "<article_url>" --select all --yes # 全部
python wx_mp.py find "<article_url>" --select 1 --yes # 第 1 组全部
python wx_mp.py find "<article_url>" --select 1.3,1.5 --yes # 点名两篇
python wx_mp.py find "<article_url>" --select 2.1-2.5 --yes # 点名一个区间
python wx_mp.py find "<article_url>" --select t --count 5 --yes # 只下最新 5 篇图文
--select 语法:all / 组号 1、1,3 / 篇号 1.3、1.3,1.5、区间 1.3-1.6 / 类型 t、v、m。
输错(如 1.99)只会提示并取消,不会退回「全部」。
--preview N 控制清单里每组显示多少条篇名(默认 30,--preview 0 全部);
--cache 不重新搜索、直接用上次的 catalog.json,编号与上次一致(搜索结果顺序会变,跨命令下载时建议加)。
全量模式:一篇链接 + 登录态(想看全号内容时)
# 有登录态时,给任意一篇该号文章链接就能列出「全部合集 + 全部历史图文」
python wx_mp.py find "https://mp.weixin.qq.com/s/xxxx" \
--cookie "wxuin=...; key=...; pass_ticket=..." -o ./archive
清单里会多出两组:
1 历史图文(微信官方接口,全量) 历史图文 213 213 0 0
2 <该号的某个合集> 图文合集 12 12 0 0
登录态怎么自动读取,见「第 0.5 步」。配好一次之后,这条命令不必再传 --cookie,
脚本会自动读取已保存的登录态。
Cookie 的四种来源(优先级从高到低):--cookie "..." → --cookie-file wx.txt →
环境变量 WX_COOKIE → ~/.wechat-mp-cookie.txt(cookie --auto / --set 写入的那个)。
另外会从命令行里那条链接的 query 中捡 key/pass_ticket/uin 作为补充。
2. 向导(wizard)
与 find 同一套逻辑,区别是查完直接进入下载问答,不额外停一步(老用法,保留兼容)。
python wx_mp.py wizard "<article_url>" -o ./archive
python wx_mp.py wizard "<album_url>" --select v --count 5 -o ./archive
find / wizard 都会顺手产出两份清单,后续可反复查阅、也可当交付物:
<out>/<公众号>/
├── 00-内容清单.md # 合集总览 + 各组前 30 条标题 + 下载配方
├── catalog.json # 机器可读清单(合集、类型、数量、链接)
└── <合集名>/… # 实际下载内容(与 album 入口结构一致)
只给 --biz 没给链接、且没有 Cookie 时,微信不提供免登录的全号合集枚举接口,向导会明确
引导用户去微信里复制合集链接(见「统计口径」)。
3. 统计篇数(先看清有多少内容)
# 单个合集:共多少条、其中图文/视频/音频各多少
python wx_mp.py stats "https://mp.weixin.qq.com/mp/appmsgalbum?__biz=XXX&action=getalbum&album_id=YYY"
# 同一公众号的多个合集:自动合并统计(图文、视频、音频分列)
python wx_mp.py stats "<album_url_1>" "<album_url_2>" "<album_url_3>"
# 只给公众号名:直接搜,能统计出该号被收录的篇目构成
python wx_mp.py stats "出师记" --pages 4
# 机器可读
python wx_mp.py stats "<album_url>" --json
按名称统计的实测输出(小号,只收到散篇):
公众号:出师记(MzI2NjQxNzMxNg==)
单篇文章 1 篇:
1. [图文] “惠考加油站”更名为“出师记”
搜狗收录,未抓正文 | 2022-04-28
小计 1 篇:图文 1 | 视频 0 | 音频/音乐 0
给的是合集链接时,会按合集分行统计(格式示意,〈〉 是占位):
公众号:〈公众号昵称〉(〈__biz〉)
合集 2 个 | 合集内条目 〈合计〉
# 合集 条目 图文 视频 音频
1 〈合集名 1〉 N N N N
2 〈合集名 2〉 N N N N
小计 N 篇:图文 N | 视频 N | 音频/音乐 N
统计口径:
- 合集内条目 = 合集里的全部内容(含图文、视频、音频),来自合集页
article_count与实际枚举结果; - 图文 / 视频 / 音频 按条目类型判定:有
vid算视频,有audio_id/时长算音频,其余算图文; - 公众号总计 需要把该号的各个合集链接都传进来。微信未提供免登录的全号文章枚举接口
(profile_ext/getalbum_list均返回no session),所以脚本只统计「已提供的合集/文章」,
并在末尾明确说明这一点——不要向用户宣称这是账号的全部历史文章。 - 按名称统计时,数量来自搜狗收录结果 + 由文章反推到的合集,不等于该号总篇数,
必须注明「非全量」。若清单里出现了合集,要说清「合集内是完整的 N 条,另有 M 条是搜到的散篇」。
想要真正的全号总量,配一次cookie --auto再给一条链接。
4. 单篇(或多篇)图文
python wx_mp.py article "https://mp.weixin.qq.com/s/AbCdEf123" -o ./archive
python wx_mp.py article "https://mp.weixin.qq.com/s/xxx" "https://mp.weixin.qq.com/s/yyy" -o ./archive
5. 整份合集(专辑)
# 先看清单,确认篇数与类型构成
python wx_mp.py album "https://mp.weixin.qq.com/mp/appmsgalbum?__biz=XXX&action=getalbum&album_id=YYY" --list-only
# 全量归档
python wx_mp.py album "https://mp.weixin.qq.com/mp/appmsgalbum?__biz=XXX&action=getalbum&album_id=YYY" -o ./archive
# 只取最近 5 条视频
python wx_mp.py album "<album_url>" --only 视频 --videos 5 -o ./archive
# 图文 3 篇 + 音频 2 条,混合取
python wx_mp.py album "<album_url>" --articles 3 --audio 2
支持图文合集、视频合集(albumType=5)、音频合集(albumType=7)。
后两种每篇是「视频贴/音频贴」,正文由客户端渲染抓不到,脚本会用清单里的 vid / audio_id
直接下载媒体,并保留原文链接。
6. 批量清单
# urls.txt:一行一个链接,# 开头为注释
python wx_mp.py batch urls.txt -o ./archive
指定篇数下载
按需组合下面三组参数,都是「取最新的 N 条」:
| 想做的事 | 参数 |
|---|---|
| 总数截断 | --limit 10(配合 --order newest 默认取最新 10 条) |
| 只下某类 | --only 视频 / --only 图文,音频 / --only all |
| 每类各取几条 | --videos 5 --articles 3 --audio 2 |
| 从第几条开始 | --start 6(跳过最新的 5 条) |
| 换成旧→新 | --order oldest(默认 newest) |
筛选后仍按所选顺序下载,--list-only 会按同样的顺序打印将要下载的清单,先核对再跑。
--limit 与每类上限同时存在时:先按每类上限挑,再整体截断到 --limit。
判断链接类型
| 链接形态 | 类型 | 处理 |
|---|---|---|
mp.weixin.qq.com/s/AbCdEf |
单篇(短链) | article |
mp.weixin.qq.com/s?__biz=..&mid=..&idx=..&sn=.. |
单篇(长链) | article |
mp.weixin.qq.com/mp/appmsgalbum?...&album_id=.. |
合集 | album,或 wizard 先列清单 |
| 只给了公众号名称(如「出师记」) | 名称 | 直接 find "出师记";搜不到再索要一条链接 |
| 主页截图 / 无任何链接 | 无输入 | 请用户给名字,或一条文章/合集链接 |
mp.weixin.qq.com/mp/profile_ext?action=home... |
公众号主页 | 从中拿不到内容,请用户改给一篇具体文章或合集链接 |
weixin.sogou.com/link?url=... |
搜狗跳转 | 脚本会自动还原成真实地址,可直接用 |
channels.weixin.qq.com/... |
视频号 | 不支持,说明只能按具体图文/合集处理 |
| 一段文字里夹着链接 | 任意 | 整段传入即可,脚本会自动挑出第一个 URL |
常用配方
# 一篇图文链接就够:先列出该号的全部合集与历史图文(只查不下)
python wx_mp.py find "https://mp.weixin.qq.com/s/xxxx" -o ./archive
# 查到后只下最新的 5 篇图文
python wx_mp.py find "<article_url>" --select t --count 5 --yes -o ./archive
# 只要正文和结构,不下载媒体(最快,先验证能不能抓到)
python wx_mp.py article "<url>" --media none
# 只要图片(素材收集)
python wx_mp.py article "<url>" --media images
# 只要音频/语音(听力材料)
python wx_mp.py album "<album_url>" --media audio -o ./听力归档
# 只要视频(合集内按 vid 逐个尝试)
python wx_mp.py album "<album_url>" --media video --limit 10
# 只出 Markdown,不要 HTML
python wx_mp.py album "<album_url>" --format md
# 幂等补跑:已下载的媒体跳过,只补新增文章
python wx_mp.py album "<album_url>" -o ./archive
python wx_mp.py album "<album_url>" -o ./archive --force # 强制重下媒体
# 机器可读摘要(便于后续处理或校验)
python wx_mp.py album "<album_url>" --limit 3 --json
# 视频直链就在页面里,不用任何登录态;想选清晰度加 --quality best/流畅/10004
python wx_mp.py cookie
python wx_mp.py album "<album_url>" -o ./archive # 只补下缺的视频,已下过的不重复下
# 只要图文/音频
python wx_mp.py album "<album_url>" --skip-video -o ./archive
# 正文被风控时临时带 Cookie(长期用请跑 cookie --auto 自动读取)
python wx_mp.py article "<url>" --cookie "wxuin=...; key=...; pass_ticket=..."
输出结构
单篇:
<out>/<标题>/
├── index.md # 带 YAML frontmatter 的正文
├── index.html # 独立样式,双击可读,媒体走本地相对路径
├── meta.json # 元信息 + 媒体统计 + 失败原因
├── images/001.jpg … # 正文图片 + cover.jpg
├── audio/audio_01.mp3
├── video/video_01.mp4
└── links.md # 仅当有资源没下载成功时生成,保留原始地址
合集:
<out>/<合集名>/
├── 00-合集索引.md # 序号 / 标题(链到本地)/ 发布时间 / 归档状态
├── manifest.json # 全量清单 + 每篇状态 + 失败原因
├── <文章1>/…
└── <文章2>/…
find / wizard 会多一层账号目录,清单放在账号层(按名称搜索到的散篇归入「散篇(未归属合集)」目录):
<out>/<公众号>/
├── 00-内容清单.md # 合集总览 + 各合集前 30 条 + 下载配方
├── catalog.json # 合集、类型、数量、链接
└── <合集名>/… # 同「合集」结构
meta.json 的 problems 是排查首选入口,逐条写明哪个媒体为什么失败。
参数速查
| 参数 | 作用 |
|---|---|
-o, --out |
输出根目录,默认 ./wechat-archive |
--media |
all(默认)/ images,audio,video 组合 / none |
--format |
both(默认)/ md / html |
--cookie / --cookie-file |
Cookie 字符串或文件(首行);也可用环境变量 WX_COOKIE,或 cookie --auto 自动读取后全局复用 |
--proxy |
形如 http://127.0.0.1:7890 |
--force |
覆盖已存在的媒体文件 |
--no-cover |
不下载封面图 |
--limit / --start |
合集总数截断 / 从第几条开始(1 起) |
--pages |
按名称搜时翻几页(PC + 移动各翻),默认 4;翻得越多搜到的篇数越多,约 3.5s/页 |
--probe |
按名搜索时探测几篇以确认该号 __biz(默认 2) |
--download |
仅 find:查完继续下载(默认只查不下) |
--select |
仅 find / wizard:all / 组号 1,3 / 篇号 1.3、1.3-1.6 / 类型 t、v、m |
--count |
仅 find / wizard:按类型下载时最多几条(点名下载时忽略) |
--preview |
清单里每组显示多少条篇名,默认 30,0 = 全部 |
--cache |
用上次的 catalog.json,不重新搜索(编号不漂移) |
--yes |
仅 find / wizard:跳过最后的确认提示 |
--only |
只处理某类:all / 图文 / 视频 / 音频,可逗号组合 |
--quality |
视频清晰度:best(默认,最大档)/ worst / 超清 / 流畅 / 10002,10102,10004,10104 |
--skip-video |
跳过视频(只要图文/音频) |
--auto |
仅 cookie:自动读取本机微信/浏览器里的登录态,不用手工复制 |
--url |
仅 cookie:配合 --auto,从这条链接的参数里捡 key/pass_ticket |
--articles / --videos / --audio |
每类最多取几条(0=不限) |
--order |
指定篇数时的取用顺序:newest(默认)/ oldest |
--concurrency |
合集并发篇数,默认 1;建议 ≤ 3,调高易触发风控 |
--delay |
篇间隔秒数,默认 1.0 |
--list-only |
合集只列清单,不下载 |
--json |
结束打印 JSON 摘要 |
--quiet |
精简输出 |
退出码:0 全部成功;2 有篇目失败(其余成功);
1 参数或入口错误(含搜狗被限流、啥也没查到)。
执行流程建议(与四步一一对应)
- 视频不需要任何前置配置:直链就在文章页里(第 0 步),下载时脚本直接取,
想换清晰度就加--quality。不要在用户没提全量需求时让他配 Cookie、抓包或扫码。
只有用户说「把该号全部合集/全部历史都列出来」时,才跑python wx_mp.py cookie
(无参即自动找一次),没命中就把那两句话交给他:
「微信里打开该号任意一篇文章 → 重跑cookie --auto」。 - 要一条链接:用户给了链接就直接跑
find "<链接>";只给名字就照开场提示语索要链接,
不要先试搜索、不要让他去找全部合集(一篇就够)。 - 列表:把终端里的清单原样贴给用户——组名、条数、每组前若干条篇名与编号。
条目多时贴汇总表 + 前 10 条,并说明「共 N 条,可--preview 0看全」。 - 确认:明确问「下全部,还是指定编号?」,等用户回答;不要在用户没表态时直接下载。
用户说「都要」→--select all;说「第 2 组的 1、3 篇」→--select 2.1,2.3。 - 下载整理:带上
--select ... --yes执行;大合集分批(--count+--order),并发 ≤3。 - 交付:单篇给
index.html;合集给00-合集索引.md;账号层给00-内容清单.md。
跑完读--json/meta.json,失败项如实说明,不要声称「全部下载成功」。 - 限定语:按名称搜来的内容必须注明「搜狗收录 N 篇,非全量」;若清单里出现了合集,
说明「合集内 N 条是完整的,另有 M 条是搜到的散篇」。走链接 + Cookie 时全量来自微信官方接口,
才可以说明是「该号全部历史图文」。
对用户说的话尽量短,例如(走链接+Cookie 时):
> 这个号(尚音爱乐)我扫到 2 组:合集《尚音爱乐精选》12 篇,另有散篇 19 篇,共 31 篇。
> 要下哪一组、下几条?也可以说「全都要」。
只给名字时:
> 这个名字没被搜到(搜狗只收录了一部分公众号)。给我一条链接更快:该号任意一篇文章
> (微信里打开 → 右上角「…」→ 复制链接),一条就够,剩下我来找。
故障处理
| 现象 | 原因 | 处理 |
|---|---|---|
触发微信风控验证 |
同 IP 请求过密 | 降 --concurrency、调大 --delay;浏览器过一次验证;或传 --cookie |
该链接仅限微信内打开 |
分享链接缺 __biz 等参数 |
请用户在微信里「复制链接」;或传 --cookie |
未解析到正文内容 且页面很小 |
视频贴/视频号,正文由客户端渲染 | 仅归档视频与链接;用合集模式按 vid 兜底 |
页面只返回了移动端骨架页 |
访问过频被限流,或确为视频贴 | 降频、稍后重试、带 --cookie;视频贴走合集 vid 兜底 |
视频 0/1,links.md 只有原文链接 |
未登录时接口不下发播放直链(返回 video_md5 而无 url_info) |
python wx_mp.py cookie 配一次登录态(第 0 步),配好后原命令重跑只补缺失视频 |
| 视频没落到本地 | 见第 0 步:多半是页面残缺(限流)、链接 sn 被截断、或直链已过期 |
用完整链接重跑一次;想省流量加 --quality worst;仍失败查 references/troubleshooting.md §4 |
音频 0/1 |
条目没有 audio_id,或该语音已失效 |
有 audio_id 时可直接下载(免 Cookie);缺失则只能留原文链接 |
合集 共 0 篇 |
合集为空、链接缺 album_id、或需要 Cookie |
核对 __biz 与 album_id;补 --cookie 重试 |
| 图片全部失败 | 防盗链、代理拦截 | 加 --proxy 或 --cookie;检查 images/ 是否有 .part 残留 |
文件名出现 _ 或截断 |
标题含 / : * ? 等非法字符,已安全化 |
正常行为,原题名保留在 index.md frontmatter |
| 按名称搜到 0 条 | 该号没被搜狗收录(小众号很常见),或名字写法不一致 | 换全名再搜一次;仍为 0 就索要一条图文/合集链接,别反复试 |
搜狗触发了人机验证 / 搜狗限流 |
搜狗按 IP 限流 | 换成微信官方接口:给一篇该号文章链接 + --cookie;或直接给合集链接。不要反复重试搜狗 |
跳转链接已失效 |
搜狗签名链接过期(清单放太久) | 重跑一次 find 生成新清单,再下载 |
| 名称搜到的篇数明显偏少 | 搜狗只收录部分历史图文 | 加 --pages 多翻几页;如实说明「非全量」;要全量需给合集链接或配 --cookie |
页面结构与接口细节见 references/wechat-page-structure.md,逐条排查见 references/troubleshooting.md。
合规要求
仅用于个人学习、教研素材整理与内容备份。归档内容版权归原公众号作者所有,
不要二次公开发布或商用;不得用于绕过付费墙、批量爬取非授权内容。
交付时保留 source 原文链接与公众号署名。
资源索引
scripts/wx_mp.py— CLI:find/wizard/stats/article/album/batch/parse七个子命令scripts/wx_search.py— 按名称搜:搜狗 PC/移动双入口 + 节流、跳转链接还原、按号名精确筛选、由文章反推__bizscripts/wx_parser.py— HTML 解析:元信息、正文块、合集 JS 字面量清单scripts/wx_media.py— 媒体下载:图片、语音、视频直链解析scripts/wx_cookie.py— 登录 Cookie:解析/保存/结构检查/实测校验(视频直链是否解锁)scripts/wx_render.py— 输出:Markdown / HTML / 合集索引 / 公众号内容清单scripts/wx_util.py— HTTP 会话、重试、文件名安全化assets/article.css— HTML 归档页样式(浅色 + 暗色)references/wechat-page-structure.md— 页面结构、接口、字段速查references/troubleshooting.md— 故障排查表