微信小程序门店数据抓包与 Python 爬虫全流程指南(以“吉祥馄饨”为例)

本文档总结了如何通过电脑端微信配合抓包工具 Reqable 获取小程序后台数据接口(API),并使用 Python 编写自动化脚本批量抓取分店名称、地址、电话、经纬度等信息并导出为 Excel 表格的完整流程。


一、 准备工作与环境要求

  1. 电脑端微信:登录个人微信账号(Windows 或 macOS 均可)。
  2. 抓包工具 Reqable:
    • 下载安装并打开 Reqable。
    • 确保右上角状态栏的三个图标(⌘ 系统代理、🌐 网络、🛡️ 根证书)均为绿色激活状态,且左侧显示绿点 Proxying on ...(正在监听)。
  3. Python 环境:安装好 Python 3.x,并安装好请求与表格处理依赖库:
    pip install requests pandas openpyxl urllib3
    

二、 第一阶段:使用 Reqable 抓取小程序接口

1. 触发小程序网络请求

  1. 如果电脑微信中已经打开了目标小程序(如“吉祥馄饨”),先点击右上角 ✕ 关闭小程序(避免读取本地缓存而不发网络请求)。
  2. 确保 Reqable 处于正在抓包状态(右上角按钮显示为“⏸ 暂停”)。
  3. 重新在微信中打开“吉祥馄饨”小程序,点击“点餐”或“切换门店”,选择目标城市(如:天津市)。

2. 从抓包列表中定位核心接口

在 Reqable 的请求列表中,会同时出现大量干扰项,可通过以下规律快速排查:

  • 排除干扰项:
    • 域名含 map.qq.com、gtimg.com:腾讯地图底图加载请求,忽略。
    • 域名含 wxgateway.com、weixinbridge.com:微信官方日志与统计上报,忽略。
  • 锁定目标接口:
    • 重点关注应用程序为 WeChatAppEx、方法为 POST 或 GET、类型图标为 {}(JSON 格式)的业务域名请求。
    • 在本案例中:
      • 请求方法:POST
      • 目标 URL:https://applet.mtcbj.com/applet/api/shop/queryShopPage/v2(从路径单词 shop/queryShopPage 即可判断为“查询门店分页接口”)。

三、 第二阶段:提取请求报文与分析响应结构

选中目标请求后,在 Reqable 右侧面板分别提取请求信息和响应信息。

1. 提取原始请求信息(右上角面板 -> 【原始】)

用于获取请求头(重点是 token 和 user-agent)以及请求体参数(payload):

POST /applet/api/shop/queryShopPage/v2 HTTP/2
host: applet.mtcbj.com
client_version: 1.0.447
xweb_xhr: 1
client_env: release
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf2541f38) XWEB/25799
accept: application/json, text/plain, */*
content-type: application/json
token: b641f4440a9a4851952908dada1cbd3fM413102457627885583
referer: https://servicewechat.com/wx469fe58febd5898f/214/page-frame.html

{"shopAddressCode":"1-120000-1201","userLon":"117.19937133789062","userLat":"39.08509826660156","deliverType":"","current":1,"size":15}
  • 参数解析:
    • shopAddressCode:城市代码(1-120000-1201 代表天津市)。
    • current:当前页码(从 1 开始)。
    • size:每页返回的门店数量(默认 15 条)。

2. 分析响应 JSON 结构(右下角面板 -> 【响应体】)

查看服务器返回的 JSON 数据,明确分页逻辑和核心字段名称:

{
  "success": true,
  "code": "00000",
  "msg": "成功",
  "data": {
    "current": 1,
    "size": 15,
    "total": 81,
    "pages": 6,
    "records": [
      {
        "shopId": 10003762,
        "shopName": "吉祥馄饨(天津肿瘤医院店)",
        "openingHoursStart": "06:30",
        "openingHoursEnd": "22:30",
        "tel": "15822868388",
        "addressCity": "天津市天津市",
        "addressDetail": "体院北环湖南里七区13号",
        "posOnline": true,
        "longitude": "117.18644335",
        "latitude": "39.08108777"
      }
    ]
  }
}
  • 核心字段对应关系:
    • 总门店数:data.total(81 家)
    • 总页数:data.pages(6 页)
    • 门店列表数组:data.records
    • 分店名称:shopName
    • 详细地址:addressDetail
    • 联系电话:tel
    • 经纬度:longitude / latitude

四、 第三阶段:编写并运行 Python 自动化爬虫脚本

⚠️ 运行前注意事项

在运行 Python 脚本前,建议先在 Reqable 右上角关闭 ⌘ 系统代理(或直接退出 Reqable),并在代码中加入 verify=False 忽略 SSL 证书校验,防止本地代理拦截导致报错。

完整 Python 源码 (fetch_shops.py)

import requests
import pandas as pd
import time
import urllib3

# 忽略SSL证书告警(防止本地抓包软件代理干扰)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def fetch_jixiang_shops():
    url = "https://applet.mtcbj.com/applet/api/shop/queryShopPage/v2"
    
    # 1. 请求头(重点保留 user-agent、token、content-type 和 referer)
    headers = {
        "client_version": "1.0.447",
        "xweb_xhr": "1",
        "client_env": "release",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf2541f38) XWEB/25799",
        "accept": "application/json, text/plain, */*",
        "content-type": "application/json",
        "token": "b641f4440a9a4851952908dada1cbd3fM413102457627885583",  # 若过期需重新抓包替换
        "referer": "https://servicewechat.com/wx469fe58febd5898f/214/page-frame.html",
        "accept-language": "zh-CN,zh;q=0.9"
    }

    all_shops = []
    current_page = 1
    total_pages = 1  # 初始值,第1次请求后会自动更新为实际总页数

    print("🚀 开始抓取吉祥馄饨门店数据...")

    while current_page <= total_pages:
        # 2. 构造分页请求参数
        payload = {
            "shopAddressCode": "1-120000-1201",  # 城市编码:天津市
            "userLon": "117.19937133789062",
            "userLat": "39.08509826660156",
            "deliverType": "",
            "current": current_page,
            "size": 15
        }

        response = requests.post(url, headers=headers, json=payload, verify=False, timeout=10)
        res_json = response.json()

        if not res_json.get("success"):
            print(f"❌ 第 {current_page} 页请求失败,返回信息:", res_json)
            break

        data = res_json.get("data", {})
        total_pages = data.get("pages", 1)
        total_count = data.get("total", 0)
        records = data.get("records", [])

        # 3. 解析单页门店列表
        for shop in records:
            raw_name = shop.get("shopName", "")
            # 清洗出括号内的纯店名,方便与其他表格直接比对
            clean_name = raw_name.replace("吉祥馄饨(", "").replace(")", "") if "吉祥馄饨(" in raw_name else raw_name
            
            all_shops.append({
                "门店ID": shop.get("shopId"),
                "分店全称": raw_name,
                "分店简称(用于对比)": clean_name,
                "详细地址": shop.get("addressDetail"),
                "联系电话": shop.get("tel"),
                "营业开始": shop.get("openingHoursStart"),
                "营业结束": shop.get("openingHoursEnd"),
                "是否营业中": "是" if shop.get("posOnline") else "否",
                "经度": shop.get("longitude"),
                "纬度": shop.get("latitude")
            })

        print(f"✅ 已抓取第 {current_page}/{total_pages} 页,累计获取 {len(all_shops)}/{total_count} 家门店")
        current_page += 1
        time.sleep(0.5)  # 礼貌延时 0.5 秒

    # 4. 导出至 Excel
    if all_shops:
        df = pd.DataFrame(all_shops)
        file_name = "吉祥馄饨_天津门店列表.xlsx"
        df.to_excel(file_name, index=False)
        print(f"\n🎉 全部抓取完成!共 {len(df)} 家门店,已保存至 【{file_name}】!")
    else:
        print("⚠️ 未获取到门店数据,请检查 token 是否过期。")

if __name__ == "__main__":
    fetch_jixiang_shops()

五、 常见问题与扩展技巧

  1. 运行报错提示“未登录”或请求失败怎么办?
    • 小程序的 token 通常具有时效性(几小时到几天不等)。如果隔天运行失败,只需打开 Reqable 重新抓一次包,把最新的 token 替换到代码的 headers 中即可。
  2. 如何抓取其他城市的门店?
    • 在小程序左上角切换为其他城市(如“上海市”或“北京市”),在 Reqable 中查看请求体里的 shopAddressCode 变成了什么编码,替换代码中的 shopAddressCode 即可抓取对应城市。

本文档由AI生成!!!

posted @ 2026-10-22 12:00  qishazi  阅读(4)  评论(0)    收藏  举报