前言
运营微信公众号多年,积累数千篇原创文章,想要完整备份或迁移到个人网站时,很多人会遇到一个难题:没有公众号后台管理员权限。官方后台导出需要运营者身份,而第三方工具往往不稳定或收费高昂。本文分享一套零权限、零成本的技术方案,只需通过Fiddler抓包配合Python脚本,即可将2000篇公众号文章批量导出为本地HTML,排版与图片完整保留。
方案原理与适用场景
本方案属于客户端抓包方案。原理是在Windows版微信中以普通读者身份浏览公众号历史文章,使用Fiddler截取微信客户端与腾讯服务器之间的通信流量,从中提取文章的真实链接,再通过Python脚本批量下载。
适用场景:
没有公众号后台登录权限,仅为普通关注者
需要备份自己或他人公众号的历史文章
导出量级在数百至数千篇之间
希望保留文章原始排版与图片素材
核心优势:无需扫码登录后台、不依赖第三方平台、支持断点续传、完全免费。
环境准备
开始前请确认以下环境与工具已就绪:
操作系统:Windows 10/11(必须,Mac版微信抓包困难)
PC版微信:Windows微信客户端(非网页版)
Fiddler Classic:免费下载安装,用于HTTPS抓包
Python 3.8+:需安装requests与beautifulsoup4库
Python依赖安装命令:
pip install requests beautifulsoup4
Fiddler自动保存配置
手动保存抓包响应极为繁琐,建议配置Fiddler自动保存功能。打开Fiddler,依次点击 Rules → Customize Rules,找到 OnBeforeResponse 函数,在函数末尾添加以下代码:
// 自动保存微信公众号历史文章接口响应
if (oSession.url.Contains("mp.weixin.qq.com") &&
(oSession.url.Contains("appmsg") || oSession.url.Contains("getmsg"))) {
var saveDir = "C:\\wechat_crawl\\responses\\";
var filename = DateTime.Now.ToString("yyyyMMdd_HHmmss_") + oSession.id + ".json";
if (!System.IO.Directory.Exists(saveDir)) {
System.IO.Directory.CreateDirectory(saveDir);
}
oSession.SaveResponseBody(saveDir + filename);
FiddlerApplication.Log.LogString("已自动保存: " + filename);
}保存后,在C盘根目录手动创建文件夹 C:\wechat_crawl\responses\。此后所有符合条件的接口响应将自动存储为JSON文件,无需人工干预。
抓包提取文章链接
第一步:配置HTTPS解密
微信流量采用HTTPS加密,必须解密才能查看内容。打开Fiddler → Tools → Options → HTTPS,勾选 Decrypt HTTPS traffic,并在弹窗中选择信任根证书。
第二步:过滤目标域名
在Fiddler右侧Filters标签中启用 Use Filters,选择 Show only the following hosts,填入:
mp.weixin.qq.com; wx.qq.com
第三步:触发抓包
打开PC版微信,进入目标公众号主页,点击全部消息。此时Fiddler左侧应开始出现请求。持续向下滚动历史文章列表,每次滚动会触发一次分页加载请求。关注URL中包含 action=getmsg 或 getmsgdata 字样的记录。
关键提示:2000篇文章约需滚动200次,建议分批次完成。每滚动20次(约200篇)暂停5至10分钟,可有效规避微信风控。
Python脚本提取文章URL
将Fiddler自动保存的所有JSON文件转移至 responses/ 文件夹,运行以下脚本提取文章标题与链接:
import json
import os
from urllib.parse import unquote
def extract_urls():
urls = []
if not os.path.exists('responses'):
print("请创建 responses 文件夹并将抓包保存的 .json 文件放入")
return
for fname in os.listdir('responses'):
if not fname.endswith('.json'):
continue
path = os.path.join('responses', fname)
try:
with open(path, 'r', encoding='utf-8') as f:
data = json.load(f)
msg_list_str = data.get('general_msg_list', '{}')
msg_list = json.loads(msg_list_str)
for msg in msg_list.get('list', []):
comm = msg.get('comm_msg_info', {})
pub_time = comm.get('datetime', 0)
info = msg.get('app_msg_ext_info', {})
if info and info.get('content_url'):
urls.append({
'title': info.get('title', '无标题').strip(),
'url': unquote(info['content_url']).replace('\\/', '/'),
'time': pub_time
})
for item in info.get('multi_app_msg_item_list', []):
if item.get('content_url'):
urls.append({
'title': item.get('title', '无标题').strip(),
'url': unquote(item['content_url']).replace('\\/', '/'),
'time': pub_time
})
except Exception as e:
print(f"解析 {fname} 出错: {e}")
seen = set()
unique = []
for u in urls:
if u['url'] and u['url'] not in seen:
seen.add(u['url'])
unique.append(u)
unique.sort(key=lambda x: x['time'], reverse=True)
with open('article_urls.json', 'w', encoding='utf-8') as f:
json.dump(unique, f, ensure_ascii=False, indent=2)
print(f"提取完成,共 {len(unique)} 篇文章,已保存到 article_urls.json")
if __name__ == '__main__':
extract_urls()Python脚本批量下载文章
获取链接列表后,使用以下脚本批量下载文章正文。脚本内置断点续传、图片本地下载与随机延时机制:
import requests
import json
import os
import time
import re
import hashlib
from bs4 import BeautifulSoup
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI '
'MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63090b13) XWEB/6945',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://mp.weixin.qq.com/mp/profile_ext?action=home'
}
def download_articles():
if not os.path.exists('article_urls.json'):
print("article_urls.json 不存在,请先运行提取脚本")
return
with open('article_urls.json', 'r', encoding='utf-8') as f:
articles = json.load(f)
os.makedirs('articles', exist_ok=True)
os.makedirs('articles/images', exist_ok=True)
progress_file = 'progress.json'
done = set()
if os.path.exists(progress_file):
with open(progress_file, 'r', encoding='utf-8') as f:
done = set(json.load(f))
total = len(articles)
for idx, art in enumerate(articles, 1):
url = art['url']
title = art.get('title', 'untitled')
if url in done:
print(f"[{idx}/{total}] 跳过已下载: {title[:40]}")
continue
try:
resp = requests.get(url, headers=HEADERS, timeout=30)
resp.encoding = 'utf-8'
safe_title = re.sub(r'[\\/*?:"<>|]', '_', title).strip()[:50]
filename = f"articles/{idx:04d}_{safe_title}.html"
soup = BeautifulSoup(resp.text, 'html.parser')
for img in soup.find_all('img'):
src = img.get('data-src') or img.get('src')
if src and 'mmbiz.qpic.cn' in src:
try:
img_data = requests.get(src, headers=HEADERS, timeout=10).content
img_hash = hashlib.md5(src.encode()).hexdigest()[:12]
img_name = f"articles/images/{img_hash}.jpg"
with open(img_name, 'wb') as imgf:
imgf.write(img_data)
img['src'] = f"images/{img_hash}.jpg"
del img['data-src']
except:
pass
with open(filename, 'w', encoding='utf-8') as f:
f.write(str(soup))
done.add(url)
with open(progress_file, 'w', encoding='utf-8') as f:
json.dump(list(done), f)
print(f"[{idx}/{total}] 完成: {title[:50]}")
delay = 3 + (hashlib.md5(url.encode()).digest()[0] % 5)
time.sleep(delay)
except Exception as e:
print(f"[{idx}/{total}] 失败: {title[:40]} - {e}")
time.sleep(15)
print(f"\n完成!成功下载 {len(done)}/{total} 篇")
if __name__ == '__main__':
download_articles()下载完成后,所有文章以独立HTML形式保存于 articles/ 目录,图片存放于 articles/images/,可直接用浏览器离线阅读。
2000篇文章实操节奏建议
针对2000篇大规模导出,建议采用分批策略,避免触发微信风控:
单日上限:400至500篇,分4至5天完成
单次滚动:每滚动20次(约200篇)暂停5至10分钟
每日验证:每天开始前先将当日抓包的JSON文件移入Python目录并运行提取脚本
文件管理:按日期建立子目录存放JSON响应,便于追溯与排错
常见问题与风控处理
滚动后不再加载新内容
此为微信"操作频繁"风控,表现为历史消息列表滚动到底后无新数据返回。解决方法是立即停止操作,等待2至24小时后自动解封,期间不要反复尝试。
下载时返回403错误
通常是请求头缺失导致。脚本中已内置微信内置浏览器UA与Referer,若仍出现403,可尝试延长单篇下载间隔至8秒以上。
文章排版丢失或图片不显示
脚本默认将微信图片域名 mmbiz.qpic.cn 的图片下载到本地并替换链接。若图片仍有外链,检查网络是否能正常访问该域名,或手动补充Cookie字段。
断点续传失效
若中途更换工作目录,需将 progress.json 一并复制到新目录,否则脚本会重新下载已完成的文件。
结语
本文方案通过Fiddler抓包与Python自动化,实现了无需后台权限的微信公众号文章批量导出。整个流程的核心在于模拟真实用户浏览行为并控制请求频率。对于2000篇量级的备份需求,建议以"小步快跑、分批验证"的方式推进,先完成50篇验证流程,确认无误后再全量执行。如需将导出的HTML转为PDF或导入CMS系统,可进一步使用Pandoc等工具进行二次转换。