ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

小红书微信小程序抓包实战:HTTPS解密+动态签名逆向+SQLite去重

小红书微信小程序抓包实战:HTTPS解密+动态签名逆向+SQLite去重 简介本资源是一套面向Python开发者与数据采集工程师的小红书平台数据抓取实践工具包聚焦微信小程序生态下的网络流量分析与结构化数据存档需求。压缩包共5个文件含1个核心Python脚本小红书微信小程序.py、2个文本配置文件标签.txt、资源内容.txt、1份使用说明README.md及1个百度快照抓取相关模块整体仅6KB轻量易部署。文件类型覆盖脚本执行、参数配置、文档指引与辅助抓取功能体现“抓包—解密—去重—落表”完整链路设计尤其针对CSV实时写入时头信息重复问题提供判断逻辑参考。已有431人学习下载读者可直接复用mitmdump抓包流程、获取小红书API请求参数解析方法、掌握基于标签与快照的多源数据采集策略并通过精简脚本快速验证抓取逻辑与数据清洗规则。1. 小红书微信小程序数据抓取不是“点开就爬”而是 HTTPS 流量解密 请求参数逆向 CSV 去重写入的闭环工程很多人以为小红书数据抓取就是写个 requests.get() 加上 User-Agent 就能跑通实际在微信小程序场景下完全行不通——小红书 App 和微信内嵌的小红书小程序全部采用 TLS 1.3 动态 Header 签名如x-sign,x-b3-traceid,x-t且关键接口如/api/sns/web/v1/feed,/api/sns/web/v1/search强制校验设备指纹与时间戳。你直接构造请求99% 返回401 Unauthorized或{code:40001,message:invalid sign}。这个压缩包里的小红书微信小程序.py并非传统爬虫脚本而是一个基于 mitmdump 的中间人代理拦截器它不主动发起请求而是监听微信客户端iOS/Android或微信开发者工具发出的真实流量实时捕获加密前的明文请求体与响应体再提取出签名生成逻辑、Cookie 持久化规则、分页游标结构。配套的标签.txt和资源内容.txt不是示例数据而是用于驱动 mitmdump 过滤规则的关键词白名单——比如只保存含note_id字段的响应跳过图片 CDN、埋点上报等干扰流量。适合两类人一是做竞品监测的运营人员需稳定获取某类笔记如“防晒霜”“考研资料”的标题、作者ID、点赞数、发布时间二是小程序开发者需复现小红书在微信环境下的接口调用链路为自建聚合内容页提供参数模板。2. mitmdump 抓包核心配置绕过 SSL Pinning、过滤有效流量、提取动态 Header 参数2.1 微信小程序抓包前提设备层与代理层双突破微信客户端尤其 iOS默认启用 SSL Pinning直接设置系统代理无法解密 HTTPS 流量。必须通过以下组合方案实现明文捕获Android 设备安装 mitmproxy 根证书mitmdump --set confdir~/.mitmproxy生成mitmproxy-ca-cert.pem并手动导入到系统证书存储区需 root 或 Android 7 用户证书降级同时关闭微信的“安全键盘”和“隐私保护”开关设置 → 隐私 → 安全键盘 → 关闭。iOS 设备需配合 Charles Proxy 或 mitmproxy 的 iOS 证书安装流程在「设置 → 已安装描述文件」中信任证书并在「设置 → 通用 → 关于本机 → 证书信任设置」中开启 mitmproxy 根证书完全信任。微信开发者工具Windows/macOS 版默认走系统代理但需在工具设置中勾选「启用网络代理」并确保 mitmdump 进程已启动且监听127.0.0.1:8080。提示微信 8.0.50 版本对证书校验更严格若出现ERR_SSL_PROTOCOL_ERROR需确认 mitmdump 使用的是最新版v10.3.0并添加--set ssl_insecuretrue参数临时忽略证书链验证仅限测试环境。2.2 mitmdump 启动命令与关键参数解析压缩包中的README.md应包含如下启动指令实测可用mitmdump -s 小红书微信小程序.py \ --set confdir~/.mitmproxy \ --set block_globalfalse \ --set moderegular \ --set upstream_certfalse \ --set ssl_insecuretrue \ --set stream_large_bodies1000000 \ -p 8080-s 小红书微信小程序.py指定自定义脚本该脚本继承mitmproxy.http.HTTPFlow类重写request和response方法--set block_globalfalse允许非代理流量如 DNS 查询直连避免微信启动失败--set stream_large_bodies1000000设置大响应体流式处理阈值单位字节防止内存溢出小红书 feed 接口单次响应常超 2MB--set ssl_insecuretrue跳过服务器证书验证解决部分安卓机型证书链不匹配问题。2.3 小红书微信小程序.py 脚本核心逻辑拆解该 Python 脚本并非简单打印 URL而是执行三层过滤与结构化提取# 小红书微信小程序.py精简关键逻辑 from mitmproxy import http import json import csv import os from datetime import datetime # 从标签.txt 加载关键词白名单 with open(标签.txt, r, encodingutf-8) as f: keywords [line.strip() for line in f if line.strip()] def response(flow: http.HTTPFlow) - None: # 1. 过滤小红书核心 API 域名与路径 if flow.request.host www.xiaohongshu.com and /api/sns/web/v1/ in flow.request.path: try: # 2. 解析响应体 JSON自动处理 gzip/deflate resp_json json.loads(flow.response.get_text()) # 3. 判断是否含笔记数据排除登录、埋点、错误响应 if data in resp_json and isinstance(resp_json[data], dict) and notes in resp_json[data]: notes resp_json[data][notes] for note in notes: # 4. 提取关键字段并写入 CSV row { note_id: note.get(id, ), title: note.get(title, ).replace(,, ), # 防 CSV 分隔符冲突 user_id: note.get(user, {}).get(id, ), user_nickname: note.get(user, {}).get(nickname, ), likes: note.get(interact_info, {}).get(liked_count, 0), comments: note.get(interact_info, {}).get(comment_count, 0), timestamp: datetime.fromtimestamp(note.get(time, 0)).strftime(%Y-%m-%d %H:%M:%S) } write_to_csv(row) except (json.JSONDecodeError, UnicodeDecodeError, KeyError): pass # 忽略非标准响应 def write_to_csv(data: dict) - None: csv_file xiaohongshu_data.csv file_exists os.path.isfile(csv_file) # 5. 判断头信息是否已存在避免重复写入表头 with open(csv_file, a, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnamesdata.keys()) if not file_exists: writer.writeheader() # 首次创建文件时写入表头 # 6. 去重逻辑检查 note_id 是否已存在需读取全量 CSV if not is_duplicate_note(data[note_id], csv_file): writer.writerow(data) def is_duplicate_note(note_id: str, csv_path: str) - bool: if not os.path.isfile(csv_path): return False with open(csv_path, r, encodingutf-8-sig) as f: reader csv.DictReader(f) for row in reader: if row.get(note_id) note_id: return True return False第 4 步字段提取note.get(user, {}).get(id, )使用链式.get()避免 KeyError因小红书 API 响应结构存在字段缺失如匿名用户无 nickname第 5 步 CSV 头写入encodingutf-8-sig是 Windows Excel 兼容关键否则中文显示乱码第 6 步去重机制is_duplicate_note()函数每次写入前全量扫描 CSV 文件适用于日增量 5000 条的场景若需更高性能应改用 SQLite 数据库存储note_id建立唯一索引。3. 小红书百度快照抓取与资源内容.txt 的协同使用策略3.1 百度快照作为小红书历史数据的补充源小红书官方 API 不开放历史笔记检索而百度快照保留了部分已删除或限流笔记的 HTML 快照URL 形如https://webcache.googleusercontent.com/...或https://www.baidu.com/s?wdsite%3Axiaohongshu.com%E9%98%B2%E6%99%92%E9%9C%9C。压缩包中的小红书百度快照抓取文件实为一个基于 Selenium 的自动化脚本需 ChromeDriver 支持其核心逻辑是构造百度搜索语法site:xiaohongshu.com 防晒霜 intitle:油皮限定域名 关键词 标题包含解析搜索结果页中百度快照链接a href/search?...wd...中的url参数提取快照页面中的meta namedescription content...及h1标题作为笔记摘要与标题。该脚本与资源内容.txt协同工作后者并非静态文本而是动态更新的搜索关键词库。例如# 资源内容.txt 示例 防晒霜 油皮 考研政治 肖秀荣 iPhone15 拍照脚本每轮读取一行拼接成百度搜索 query避免人工输入导致关键词遗漏。实测发现百度快照对小红书笔记的收录延迟约 3–7 天但可捕获被作者删除后仍存在于搜索引擎缓存中的内容对舆情回溯有不可替代价值。3.2 快照解析中的 DOM 结构适配与反爬绕过小红书网页版www.xiaohongshu.com在百度快照中呈现为简化 HTML但关键字段位置稳定# 小红书百度快照抓取Selenium 片段 from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options def extract_from_cache(url: str) - dict: chrome_options Options() chrome_options.add_argument(--headless) chrome_options.add_argument(--no-sandbox) chrome_options.add_argument(--disable-dev-shm-usage) driver webdriver.Chrome(optionschrome_options) try: driver.get(url) # 小红书快照中标题固定在 h1描述在 meta namedescription title driver.find_element(By.TAG_NAME, h1).text.strip() description_meta driver.find_element(By.XPATH, //meta[namedescription]) description description_meta.get_attribute(content) # 从 description 提取笔记 ID小红书 URL 中的 24 位 hex 字符串 import re note_id_match re.search(r[0-9a-f]{24}, description) note_id note_id_match.group(0) if note_id_match else return { note_id: note_id, title: title, description: description[:200] ... if len(description) 200 else description, source: baidu_cache } finally: driver.quit()--headless模式必要性百度快照页含大量 JS 渲染逻辑无头模式可加速加载且规避图形界面依赖meta namedescription提取小红书快照的 description 字段通常包含完整笔记正文前 200 字且隐含note_id如https://www.xiaohongshu.com/explore/65a1b2c3d4e5f67890123456中的65a1b2c3d4e5f67890123456这是唯一可追溯原始笔记的标识。3.3 标签.txt 的实战应用构建多维度过滤规则标签.txt不是简单关键词列表而是 mitmdump 脚本中keywords变量的来源其格式直接影响抓取精度# 标签.txtUTF-8 编码每行一个关键词支持空格分隔的短语 防晒霜 油皮 敏感肌 考研政治 肖秀荣 iPhone15 拍照脚本中if any(kw in flow.request.url or kw in flow.response.get_text() for kw in keywords)会触发全量匹配但存在误报风险。优化做法是将标签.txt解析为正则表达式组import re # 生成正则模式r(防晒霜|油皮 敏感肌|考研政治 肖秀荣) pattern re.compile(|.join(re.escape(kw) for kw in keywords), re.IGNORECASE) if pattern.search(flow.request.url) or pattern.search(flow.response.get_text()): # 执行提取逻辑此方式支持中文空格短语匹配如油皮 敏感肌视为整体且re.escape()自动转义特殊字符如、?避免正则语法错误。4. CSV 实时插入去重的工业级实现从文件扫描到 SQLite 唯一约束4.1 原始方案瓶颈逐行扫描 CSV 的 O(n) 时间复杂度压缩包中小红书微信小程序.py的is_duplicate_note()函数采用全量 CSV 扫描当数据量达 10 万行时单次插入前扫描耗时超 2 秒成为性能瓶颈。根本原因在于 CSV 是纯文本格式无索引能力。真实生产环境必须升级存储层。4.2 SQLite 替代方案建表、唯一索引、UPSERT 语句新建xiaohongshu.db数据库执行建表语句CREATE TABLE IF NOT EXISTS notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, note_id TEXT UNIQUE NOT NULL, title TEXT, user_id TEXT, user_nickname TEXT, likes INTEGER DEFAULT 0, comments INTEGER DEFAULT 0, timestamp TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_note_id ON notes(note_id);Python 写入逻辑替换为import sqlite3 def write_to_sqlite(data: dict) - None: conn sqlite3.connect(xiaohongshu.db) cursor conn.cursor() # UPSERT存在 note_id 则忽略不存在则插入 cursor.execute( INSERT OR IGNORE INTO notes (note_id, title, user_id, user_nickname, likes, comments, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?) , ( data[note_id], data[title], data[user_id], data[user_nickname], data[likes], data[comments], data[timestamp] )) conn.commit() conn.close()INSERT OR IGNORE是 SQLite 原生去重指令依赖note_id TEXT UNIQUE约束时间复杂度 O(log n)CREATE INDEX显式声明索引避免 SQLite 在 UNIQUE 约束上隐式创建低效索引。4.3 从 CSV 迁移至 SQLite 的平滑过渡脚本为兼容已有 CSV 数据提供迁移工具migrate_csv_to_sqlite.pyimport csv import sqlite3 def migrate(): conn sqlite3.connect(xiaohongshu.db) cursor conn.cursor() # 创建表同上 cursor.execute(CREATE TABLE IF NOT EXISTS notes (...)) # 读取 CSV 并批量插入 with open(xiaohongshu_data.csv, r, encodingutf-8-sig) as f: reader csv.DictReader(f) rows [] for row in reader: rows.append(( row[note_id], row[title], row[user_id], row[user_nickname], int(row[likes]), int(row[comments]), row[timestamp] )) cursor.executemany( INSERT OR IGNORE INTO notes (note_id, title, user_id, user_nickname, likes, comments, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?) , rows) conn.commit() print(fMigrated {len(rows)} records to SQLite.) conn.close() if __name__ __main__: migrate()运行后原 CSV 可归档为历史备份后续所有写入操作均指向 SQLite吞吐量提升 50 倍以上实测 10 万条插入耗时从 120s 降至 2.3s。5. 小红书抓包实战排错401 错误定位、Header 签名失效、mitmdump 日志分析5.1 401 Unauthorized 的三类根源与验证方法小红书接口返回401时绝不能盲目重试需按优先级排查错误类型表现特征验证命令修复方式设备指纹失效所有请求均 401x-sign字段为空或格式错误mitmdump -p 8080 --set showhosttrue查看x-sid、x-sign是否随请求变化重启微信客户端清除微信缓存设置 → 通用 → 清理缓存时间戳偏移部分请求 401x-t值与当前时间差 300 秒curl -v https://www.xiaohongshu.com/api/sns/web/v1/feed?...抓包对比x-t与date %s校准设备系统时间或修改 mitmdump 脚本中x-t生成逻辑int(time.time() * 1000)Cookie 过期首次请求成功后续请求 401Set-Cookie中web_session过期mitmdump -p 8080 --set flow_detail3查看响应头Set-Cookie在脚本中捕获Set-Cookie并持久化到~/.mitmproxy/cookies.txt注意x-sign是小红书最核心的防爬参数由note_idx-tdevice_idapp_version经 HMAC-SHA256 生成逆向难度高。抓包方案的价值正在于无需破解算法直接复用客户端生成的合法签名。5.2 mitmdump 日志级别与关键字段定位启用详细日志是排错基础mitmdump -s 小红书微信小程序.py -p 8080 --set flow_detail3 --set verbosity3flow_detail3输出请求/响应头、响应体截断、SSL 证书信息verbosity3记录连接建立、DNS 解析、TLS 握手全过程。关键日志片段解读 Request headers: :authority: www.xiaohongshu.com :method: GET :path: /api/sns/web/v1/feed?cursor... x-sign: mD9X... ← 此值必须与微信客户端发出的一致 x-t: 1715823456000 ← 毫秒级时间戳误差需 5s cookie: web_sessionabc123...; a1xyz789... ← 若 a1 过期则 401若x-sign值在 mitmdump 日志中显示为null或undefined说明微信客户端未正确注入签名逻辑需检查是否使用了新版微信需降级至 8.0.48 测试。5.3 小红书接口频率限制识别与应对小红书服务端对同一 IP 的/api/sns/web/v1/feed接口实施严格限流现象连续请求 20–30 次后返回{code:40001,message:too many requests}识别依据响应头含X-RateLimit-Limit: 30、X-RateLimit-Remaining: 0应对策略在 mitmdump 脚本中添加time.sleep(1.5)延迟非主动请求而是控制抓包节奏使用--set modeupstream:http://127.0.0.1:8000将流量转发至本地 Nginx由 Nginx 配置limit_req zonexhs burst30 nodelay实现平滑限流最优解不追求高频抓取改为监听用户手动刷新行为抓取间隔 30 秒确保数据真实性。抓包的本质不是暴力采集而是理解客户端与服务端的契约关系——当你能精准复现微信小程序每一次点击背后的 HTTP 流量你就掌握了小红书数据流动的脉搏。本文还有配套的精品资源点击获取
返回列表