返回 Skill 列表
extension
分类: 数据与分析需要 API Key

微信公众号文章抓取

抓取微信公众号文章为可独立阅读的 HTML 文件。适用于用户需要备份、归档或镜像微信公众号文章的场景(来自 IMA、已知 URL 或任何来源),当 IMA 中有 media_type=3 或 media_type=6 的文章时,当 IMA 客户端无法访问文章(限流 220021 / 文件拒绝 220030)时,或需要离线浏览原本被微信付费墙/登录墙遮挡的文章时使用。

person作者: user_2015f712hubcommunity

微信公众号文章抓取

抓取微信公众号文章,保留原始页面结构,修复反爬 CSS(#js_content { visibility: hidden }),并将每篇文章保存为独立的 HTML 文件,可在任意浏览器中离线打开。

实测验证: 2026-06-19 从真实 IMA 知识库(yxxf_cloud,共 94 项)中经受 84 篇文章的实战检验:41 篇成功获取并修复,43 篇限于 IMA API 限制(220021 配额、220030 文件拒绝)仅保留元数据。

When to Use(适用场景)

  • 用户想备份/归档/镜像微信公众号文章
  • 文章在 IMA 中,且 media_idwechatarticle_ 开头(涵盖 media_type: 3 笔记 media_type: 6 外链)
  • 用户手头有微信文章 URL(来自聊天记录、浏览器历史、IMA 快照)
  • IMA 网页版被限流(220021)或文件级拒绝(220030)
  • 需要离线阅读保留原始布局(文本 + 图片 + 代码块)的 HTML

不适合的场景:

  • 文章不在 IMA 中手头没有 URL — 参见 references/wechat-discovery.md;搜狗是唯一的公开来源且会主动反爬
  • 纯 Markdown / PDF / 基于图片的文章(使用 ocr-and-documents 技能)
  • 激进修绕 IMA 配额限制(会被当日封禁)

快速开始

模式一:单个 URL(无需 IMA)

python scripts/fetch_wechat.py --url "https://mp.weixin.qq.com/s/abc123xyz" --out ./article.html

冒烟测试 URL(确认可用):https://mp.weixin.qq.com/s/_At08VDpI_I5rH3EETfN1g

模式二:从 IMA 知识库批量抓取

# 1. 安装 Python 依赖
pip install requests beautifulsoup4

# 2. 确认 IMA 凭据存在(仅用于 --items 模式)
test -f ~/.config/ima/client_id && test -f ~/.config/ima/api_key \
  && echo "✅ IMA credentials OK" || echo "⚠️  see ima-skill"

# 3. 运行批量抓取
python scripts/fetch_wechat.py \
  --items ~/ima-kb-items-backup.json \
  --out ~/wechat-archive

每项必需字段(在 JSON 导出中):

{ "media_id": "wechatarticle_d891bce82003b...", "media_type": 6, "title": "..." }

筛选规则: 使用 media_id.startswith('wechatarticle_') — 而非 media_type。参见常见陷阱第 8 条。

工作原理(架构)

┌─────────────────────┐                  ┌────────────────────┐
│  IMA 知识库         │                  │  输出 HTML 文件    │
│  (items.json)       │                  │                    │
└──────────┬──────────┘                  └─────────▲──────────┘
           │                                      │
           │ ① 筛选: media_id 以                   │ ④ 写入独立 HTML
           │    "wechatarticle_" 开头              │    在 <head> 中注入
           │                                      │    4 项修复
           ▼                                      │
┌─────────────────────┐                  ┌─────────┴──────────┐
│ 第一步: 获取 URL    │                  │ 第三步: 获取 HTML  │
│ POST /openapi/wiki/ │                  │ curl + UA:         │
│ v1/get_media_info   │                  │  MicroMessenger     │
│                     │                  │  Mobile UA          │
│ → data.url_info.url │                  │                    │
└──────────┬──────────┘                  └─────────▲──────────┘
           │                                      │
           │ ② mp.weixin.qq.com/s/xxx URL         │ ③ GET with Referer
           └──────────────────────────────────────┘

两步抓取: IMA API 返回 URL,然后用 curl 获取微信页面。直接访问微信若未使用移动端 MicroMessenger UA 将得到精简版——没有图片、没有格式、没有内容。

保留原始 HTML 原样: 不要转换为 Markdown。放入模板中。保持 div、段落、引用、图片、代码块、格式 1:1 不变。

四项修复(注入到 <head> 中)

输出的 HTML 是原始微信页面,在 <head> 中注入了 4 个 CSS/样式块。每项修复独立且幂等。完整的 CSS 代码、每条规则的原理以及正则模式详见 references/css-fixes.mdreferences/noise-stripper.md

| # | 修复项 | 默认 | CLI 参数 | 作用 | |---|--------|------|----------|------| | 1 | CSS 可见性 | ✅ 开启 | — | 覆盖 #js_content { visibility: hidden },使正文无需 JS 即可显示 | | 2 | 桌面布局 | ✅ 开启 | — | 重新适配移动端页面为桌面端浏览(最大宽度 780px,字号 17px,行高 1.75) | | 3 | 封面移除 | ✅ 开启 | --keep-cover | 去掉顶部的 <div id="js_row_immersive_cover_img"> + alt="cover_image" 的 img | | 4 | 无关元素剔除 | ✅ safe | --noise-level safe\|normal\|strict | 剔除工具栏、二维码、广告、相关文章、评论 |

无关元素剔除级别(递增——strict = safe + normal + strict):

| 级别 | 剔除的内容 | 保留的内容 | |------|-----------|-----------| | 🟢 safe | 底部工具栏、PC 二维码、广告容器、赞赏提示、加载动画 | 标题、作者、日期、正文、所有图片 | | 🟡 normal | + 元信息、作者卡片、小说卡片、分享提示、标签 | 标题、正文、所有图片 | | 🔴 strict | + 原创标、相关文章、评论、历史、<mp-*> H5 网页组件 | 仅正文 + 图片 |

为什么用 <head> 中的 CSS 而不是修改正文: 微信的反爬 CSS 存在于原始 HTML 中。我们使用 !important 覆盖而非删除。原始源码不触动,修复从外部施加——更易调试、更易更新。

Common Pitfalls(常见陷阱)

1. 220021 配额耗尽get_media_info 返回 {"code": 220021, "msg": "资料获取次数已达上限"}。每个知识库每天有限额(约 50-100 次)。等明天再用 --filter 对剩余项重跑。不要重试——每次调用都计费。→ 完整表格见 references/ima-api-codes.md

2. 220030 文件级拒绝{"code": 220030, "msg": "该文件获取失败"}。IMA 已将这篇特定文章加入黑名单。无法通过 API 恢复。可选方案:打开 IMA 桌面客户端手动复制 HTML,或跳过。配额可能还有余量——可以继续抓取下一篇文章。

3. 获取到精简版 HTML(无图片、无内容) — 获取到的页面约 10 KB,缺失 <div class="rich_media_content">原因: 当 UA 看起来不像移动端微信客户端时,微信返回精简版页面。修复: 使用移动端 MicroMessenger UA(已内置在脚本中)。桌面端 UA 会获取到最简版本。

4. CSS 修复未生效 — 正文文本仍只有约 132 字符(仅标题 + 元信息)。检查 grep 'wechat-fetch-fix' article.html——如果缺失,说明脚本的 <head> 后备注入未生效。如果存在,检查微信 CSS 的特异性(修复使用了 !important,通常应能胜出)。

5. 桌面端布局显示异常 — 文本固定在 14px 左边缘,没有最大宽度,没有行高,出现了类似 autoTypeSetting24psection 的奇怪类名。原因: 移动端 MicroMessenger UA 返回的是移动端版本;桌面浏览器没有微信的移动端 CSS。修复: v2.0+ 注入 wechat-desktop-fix 样式块。可用 grep 'wechat-desktop-fix' article.html 验证。如果缺失,说明文件来自 v1.1 之前的抓取——重新抓取或从更新的文件复制该块。

6. 按 media_type 筛选结果为零media_type=6 是一个宽泛的分类,包含普通网页链接、PDF、图片 以及 微信公众号文章。使用 media_id.startswith('wechatarticle_') 是可靠的筛选方式。

7. 搜狗 1-2 次请求后返回 302 /antispider/Set-Cookie: black_passportid=1 是终止信号(IP 级封禁数小时)。不要尝试 Selenium/Playwright——指纹检测过于激进。决策树见 references/wechat-discovery.md

8. 嵌套 div 破坏简单正则剔除re.subn(r'<div id="X">.*?</div>', '', html) 在 div 嵌套时会悄悄留下部分匹配。请使用基于栈的匹配器,向前遍历计数 <div</div 直到深度归零。参见 fetch_wechat.py 中的 strip_element_by_id()。同样适用于 <table><section><pre><a>——任何可能存在嵌套的标签对。

9. <mp-*> H5 网页组件在严格剔除后仍存在 — 可能是推荐区块使用了剔除器未识别的形式。识别新元素(总是以 mp- 为前缀),添加成对和自闭合模式,用注入夹具测试。→ 完整 H5 组件目录见 references/wechat-h5-components.md

Verification Checklist(验证清单)

每篇文章:

  • [ ] 正文文本可见(不仅仅是标题 + 元信息)——证明 CSS 修复生效
  • [ ] 图片能加载——证明 data-src → src 修复生效
  • [ ] 原始布局保留(div、引用、代码块)
  • [ ] 顶部的源 URL 链接指向 mp.weixin.qq.com
  • [ ] 无控制台错误(DevTools → 控制台)

自动冒烟测试(文本长度):

import re
html = open('article.html').read()
body_text = re.sub(r'<[^>]+>', '', html)
assert len(body_text) > 300, f"正文太短 ({len(body_text)} 字符) ——修复未生效!"

每项剔除规则(修改后):

使用注入测试模板——在已知良好的 HTML 中合成包含可疑元素的夹具,运行剔除器,用结构正则(而非子串计数)验证。完整模板见 references/injection-testing.md

每个批次:

  • [ ] IMA 凭据存在于 ~/.config/ima/client_id~/.config/ima/api_key
  • [ ] 输出目录可写
  • [ ] 配额剩余:在批量运行前先用一次 get_media_info 测试
  • [ ] 至少有一篇文章在修复后 正文文本 > 300 字符

参考资料

| 文件 | 内容 | |------|------| | references/css-fixes.md | 可见性、桌面布局、封面移除的完整 CSS(11 条规则) | | references/noise-stripper.md | 所有 3 个级别 × 规则,适用于嵌套 div 的基于栈的匹配器 | | references/injection-testing.md | 如何使用合成夹具验证剔除规则 | | references/ima-api-codes.md | IMA 错误码(220021、220030、200001)、配额经验 | | references/wechat-discovery.md | IMA 之外:搜狗、web.archive.org、决策树 | | references/wechat-h5-components.md | 所有已知的 <mp-*> 网页组件、Shadow DOM 行为 |

脚本

| 脚本 | 用途 | |------|------| | scripts/fetch_wechat.py | 主抓取器 —— --url--items 模式,注入全部 4 项修复 | | scripts/strip_noise.py | 独立无关元素剔除器(可应用于旧 HTML 文件) | | scripts/remove_cover.py | 独立封面移除器(可应用于 v1.2 之前的文件) | | scripts/verify_fix.py | 自动化验证(正文文本长度、图片数量) |

相关技能

  • ocr-and-documents — 用于 PDF 和扫描文档(不同类型的内容)
  • ima-skill — 本技能依赖的 IMA OpenAPI 客户端(用于 --items 模式)
  • plan — 用于带配额感知的批量抓取规划

更新日志

v3.1.0 — 补全 3 个必需章节

修 SKILL.md 规范合规:

  • 修 name 字段不匹配(wechat-article-fetcherwechat-article-fetcher-cn,匹配目录名)
  • 加 3 个英文章节别名(满足 refactor-skill-to-spec 验证脚本)
    • ## When to Use(适用场景)
    • ## Common Pitfalls(常见陷阱)
    • ## Verification Checklist(验证清单)
  • 字符数 8,516 → 8,500+(基本不变)

行为无变化: 所有命令、脚本、修复、配置完全保留

v3.0.0— 重大中文化更新

  • displayName 改为「微信公众号文章抓取」
  • description、tags 及正文全部英文内容转换为中文
  • 代码块、CLI 命令、文件名、技术参数保留原文
  • scripts/ 中 Python 代码注释改为中文
  • 版本从 v2.0.1 升级至 v3.0.0
  • license 保持 GPL-3.0

v2.0 — 重构为对等格式

  • SKILL.md: 31.8k → 9.5k 字符(目标为 8-15k 对等范围)
  • 4 项修复合并为 2 个参考文件(css-fixes.mdnoise-stripper.md
  • 常见陷阱:11 → 9(去重,保留最具操作性的)
  • H5 网页组件 → wechat-h5-components.md(原内联,现独立文件)
  • 注入测试模板 → injection-testing.md(原内联,现可复用)
  • 快速开始:增加了冒烟测试 URL(原缺失)
  • "无 URL" 决策树 → wechat-discovery.md(原内联且重复)

无行为变更: 所有 4 项修复、所有 CLI 参数、所有脚本逻辑与 v1.4 保持一致。