公众号图片打包下载
给一篇微信公众号文章链接,产出文章全部正文原图的 zip 包 + 图片清单 manifest.md。面向做设计素材、二创、存档的用户——他们要的是可用的图片文件,不是正文 Markdown(那请用 wechat-article-ingest)。
功能
- 抓原图:解析正文
<img>的data-src(微信真实图床地址,兼容src直链),路径末段/640改/0拉取原图尺寸 - 保真:
gif自动去掉tp=webp参数,拿到原始 GIF 动图(魔数校验GIF89a),不是 webp 压缩版 - 防断链:微信服务器断流/超时自动重试 3 次;mmbiz 防盗链 403 时自动加
Referer重试 - 交付:按文章顺序命名
01.jpg 02.png …+manifest.md清单(序号/文件名/大小/原始URL)+文章标题.zip - 零依赖:纯 Python 标准库(urllib/re/json/zipfile/ssl),运行环境开箱即用
工作流程(agent SOP)
- 校验链接:确认用户给的是
mp.weixin.qq.com域名链接(/s/xxxx短链或__biz&mid&idx&sn参数式均可)。不是则直接告知用户"需要公众号文章链接",不要执行。 - 执行完整打包(默认动作,测试或用户只要部分图时才加参数):
bash python3 "${SKILL_DIR:-$PWD/.workbuddy/skills/wechat-imgs-pack}/scripts/fetch_wechat_imgs.py" "https://mp.weixin.qq.com/s/xxxx" -d ./wechat_imgs/某文章名 - 读取输出:脚本最后一行输出 JSON(
title/total/ok/zip/zip_size/files),stderr 有逐张下载日志。向用户报告:"共抓到 N 张图,成功 M 张,打包为 xxx.zip(大小)"。 - 交付:把 zip 绝对路径给用户;若在 当前运行环境,提示 zip 可直接下载。manifest.md 已包含在 zip 内,也在输出目录单独保留。
- 按需变体:
- 用户只想"先看看效果/几张试试" → 加--limit 3
- 用户明确说"不要 zip,散图就行" → 加--no-zip - 失败处理:
-抓取失败:…环境异常→ 微信风控,等 1~2 分钟换时间重试一次;仍失败则如实告知(运行环境 IP 被临时限流),建议用户稍后再试
-共抓到 0 张→ 文章是纯文字/图片动态加载,如实告知
- 个别图下载失败 → zip 与清单照常生成,失败项在 manifest.md 中标 ❌ 并注明原因,向用户说明缺了哪几张
命令参考
# 标准用法:抓全部图片并打包
python3 scripts/fetch_wechat_imgs.py "<mp.weixin.qq.com 文章链接>" -d <输出目录>
# 只下前 N 张(测试用)
python3 scripts/fetch_wechat_imgs.py "<链接>" -d <输出目录> --limit 3
# 只下载不打包(散图 + manifest.md)
python3 scripts/fetch_wechat_imgs.py "<链接>" -d <输出目录> --no-zip
| 参数 | 说明 |
|---|---|
url(位置参数) |
公众号文章链接,必须是 mp.weixin.qq.com 域名 |
-d, --dir |
输出目录,默认 ./wechat_imgs_download;图片、manifest.md、zip 都放这里 |
--limit N |
只下载前 N 张,0=全部 |
--no-zip |
不生成 zip,只落图片和 manifest.md |
输出约定:图片按正文出现顺序 01.扩展名 起名;扩展名由 URL wx_fmt 参数 + 下载后魔数双重判定(jpeg→jpg/png/gif/webp,其他格式魔数兜底);zip 名为清洗后的文章标题(非法字符替换为空格,超 30 字截断)。
示例对话
例 1:打包配图
> 用户:https://mp.weixin.qq.com/s/f5YevQkTvCXTwQYMk0x-PA 这篇的配图能都下给我吗?做参考素材用。
>
> Agent:好的,这就抓取打包。→ 执行标准命令 → "共抓到 13 张图,成功 13 张(含 7 张 GIF 动图原图),打包为《公众号图文底部签名区样式大全》.zip(大小 15.91 MB),路径:./wechat_imgs/…/《公众号图文底部签名区样式大全》.zip,清单 manifest.md 已含在包内。"
例 2:先试几张
> 用户:先随便下 3 张看看图质。
>
> Agent:→ 加 --limit 3 执行 → "试抓前 3 张:01.gif(66.3 KB)、02.gif(41.8 KB)、03.png(205.5 KB),均为原图尺寸,打包 308.2 KB,路径 xxx。满意的话我再抓全部 13 张。"
例 3:不要打包
> 用户:图直接放文件夹就行,别压缩了。
>
> Agent:→ 加 --no-zip 执行 → "已下载 12 张原图 + manifest.md 清单,保存在 ./wechat_imgs/xxx/,未打包。"
运行环境
- 脚本:
scripts/fetch_wechat_imgs.py(相对技能根目录) - Python:3.9+,脚本只用标准库,不需要 pip 安装任何包
- 外部命令:无
注意事项
以下为 2026-10 实测结论(测试样本:两篇设计类公众号文章,合计 25 张图,25 张全部成功):
- 防盗链现状:mmbiz.qpic.cn 实测仅带桌面 UA 即可下载,未触发 403,无需登录/Cookie。脚本仍保留"失败后加
Referer: https://mp.weixin.qq.com/重试 2 次"的保险逻辑,勿删。 - gif 保真关键:微信 HTML 里的 gif 地址若带
tp=webp参数,直接请求会拿到 webp 压缩版(动图变静态)。脚本已自动剥离tp/wx_lazy/wx_co/wxfrom参数,并用魔数校验,若期望 gif 却返回 webp 会自动换候选重试。 - 原图增强:图片路径末段数字是缩略宽度(
/640),改为/0可取原图,实测同一张 png 210 KB(原图)vs 184 KB(640 版)。脚本默认请求/0,失败回退原始 URL。 - 微信限频/断流:同一 IP 连续请求大页面时,微信服务器会中途断流(
IncompleteRead)或超时——实测抓 3.8MB 页面时出现,脚本已自动重试 3 次解决。脚本为串行下载(每张间隔短),请勿并发跑多篇;若仍报"网络请求失败",等 1~2 分钟再试。 - 风控验证页:微信偶尔返回"环境异常"验证页,脚本会明确报错,重试无效时如实告知用户,不要反复硬试。
- 抓取范围:只抓正文区(
js_content)的<img>,不含封面图(og:image)、不含 CSS 背景图(background-image)、不含评论区图片;<img data-src>优先,无 data-src 时回退src直链;data:base64 与 JS 拼接串自动过滤。 - 纯文字文章会报"共抓到 0 张",属正常;视频号内容、非 mp.weixin.qq.com 链接不支持(exit code 2)。
- 版权合规:仅供个人学习、研究与二创参考,图片版权归原作者所有,商用请取得授权;不要用于批量爬取。