一、小程序爬虫核心技术认知
- 小程序与传统 Web 爬虫的核心差异
传统 Web 爬虫主要针对 PC 端或移动端网页,基于 HTML 解析、Cookie 维持、HTTP/HTTPS 请求模拟即可完成大部分数据抓取工作。而小程序爬虫的核心差异体现在三个方面:
传输协议与数据格式:小程序后端接口多采用 JSON 格式传输数据,极少返回完整 HTML 页面,无需进行 DOM 解析,重点在于接口参数解密与响应数据提取;
身份验证机制:小程序普遍采用 wx.login 生成的 code、session_key、openid 等进行用户身份验证,部分接口还会携带自定义签名(如 sign 参数),防止非法请求;
抓包与调试限制:小程序运行在微信的沙箱环境中,默认禁止外部工具直接抓包,且存在反爬机制(如接口频率限制、设备指纹验证、参数时效性校验)。 - 小程序爬虫必备核心技术栈
完成某程旅行小程序爬虫开发,需要掌握以下核心技术:
抓包技术:使用 Fiddler、Charles 等工具配置代理,突破微信沙箱环境限制,捕获小程序的网络请求;
接口分析技术:解析请求头、请求参数、响应数据的结构,识别加密参数(如 sign、timestamp、nonce)的生成逻辑;
请求模拟技术:基于 Python 的 requests、aiohttp 库模拟小程序的 HTTP/HTTPS 请求,维持会话状态;
数据处理技术:使用 json、pandas 库解析、清洗、存储抓取到的 JSON 数据;
反反爬应对技术:实现请求频率控制、UA 伪装、签名参数模拟等,规避小程序的反爬策略。
二、前期准备工作 - 环境与工具搭建
开发环境:Python 3.8+(兼容性好,第三方库生态完善),推荐使用 Anaconda 管理环境;
抓包工具:Charles(跨平台,操作友好,适合小程序抓包);
Python 第三方库:安装必备依赖
requests:模拟 HTTP/HTTPS 请求;
pandas:数据清洗与存储;
pycryptodome:应对可能的接口数据加密(如 AES、DES);
fake-useragent:生成随机 User-Agent,伪装请求来源。 - Charles 抓包配置(关键步骤)
小程序运行在微信环境中,需配置代理才能捕获其网络请求,步骤如下:
打开 Charles,进入「Proxy」→「Proxy Settings」,设置端口(如 8888),勾选「Enable transparent HTTP proxying」;
配置电脑本机代理,将 HTTP/HTTPS 代理指向 Charles 的 IP 与端口(本地 IP+8888);
安装 Charles 证书:进入「Help」→「SSL Proxying」→「Install Charles Root Certificate」,完成证书信任配置(重点:移动端 / 微信需安装对应证书);
微信小程序抓包配置:打开手机微信(或电脑微信模拟器),连接与电脑同一局域网,配置手机代理为电脑 IP+8888,安装 Charles 手机证书;
开启 SSL 代理:在 Charles 中右键点击目标请求(某程旅行小程序相关),选择「Enable SSL Proxying」,即可捕获 HTTPS 加密请求。 - 合规性声明
重要提醒:本文所有技术内容仅用于技术研究与学习,不得用于商业用途或非法数据抓取。
某程旅行小程序的所有数据均受《中华人民共和国著作权法》《网络安全法》保护,抓取前需确认是否获得平台授权;
不得突破平台的反爬机制,不得进行高频次请求影响平台服务器正常运行;
抓取的数据不得用于传播、售卖、竞品分析等违规场景,仅可用于个人技术研究。
三、某程旅行小程序接口分析 - 目标接口定位
打开某程旅行小程序,进入「酒店」板块,选择某一城市(如北京),筛选入住 / 离店日期,触发数据加载。此时在 Charles 中可捕获到对应的酒店列表接口,特征如下:
请求方式:POST(部分接口为 GET);
请求域名:多为某程官方域名(如api.ctrip.com,实际需以抓包结果为准);
请求头:包含User-Agent(小程序专属 UA,格式如Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.30(0x18001e31) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/3.9.5.81)、Referer、Content-Type(application/json)等;
请求参数:包含cityId(城市 ID)、checkInDate(入住日期)、checkOutDate(离店日期)、pageNum(页码)、pageSize(每页条数)、sign(签名参数)、timestamp(时间戳)等;
响应数据:JSON 格式,包含酒店 ID、酒店名称、价格、评分、地址等核心字段,无复杂加密(部分接口可能对响应数据进行 AES 加密,需进一步解析)。 - 关键参数解析
本次实战以未加密的公开接口(模拟场景,贴合技术学习需求)为例,核心参数说明:
参数名
含义
取值示例
cityId
城市 ID
1(北京)
checkInDate
入住日期
2026-01-15
checkOutDate
离店日期
2026-01-18
pageNum
页码
1
pageSize
每页条数
20
timestamp
时间戳(毫秒级)
1736985600000
sign
签名(简化版,实际为参数拼接加密)
md5(cityId+checkInDate+timestamp+secret)
其中,sign参数是小程序接口的核心反爬手段之一,通常由平台后端约定的 secret 密钥 + 请求参数拼接后进行 MD5/SHA256 加密生成。本次实战中,我们模拟简化版签名生成逻辑(实际场景需通过逆向工程解析小程序源码获取完整签名逻辑)。
四、实战:某程旅行小程序酒店数据爬虫开发 - 爬虫核心流程设计
定义配置参数(城市 ID、日期、页码、请求域名等);
实现签名参数生成逻辑(模拟 MD5 加密);
伪装请求头,构造完整请求参数;
发送 HTTP 请求,获取响应数据;
解析 JSON 响应,提取核心酒店数据;
数据清洗与存储(保存为 CSV 文件);
实现多页数据抓取,添加请求延迟,规避反爬。 - 完整实现代码
python
运行
```
import requests
import pandas as pd
import time
import hashlib
from fake_useragent import UserAgent
from typing import List, Dict
class CtripMiniProgramSpider:
"""
某程旅行小程序酒店数据爬虫(仅用于技术学习)
"""
def init(self):
# 基础配置
self.base_url = "https://api.ctrip.com/hotel/list" # 模拟接口,实际以抓包为准
self.city_id = "1" # 北京城市ID
self.check_in_date = "2026-01-15" # 入住日期
self.check_out_date = "2026-01-18" # 离店日期
self.page_size = 20 # 每页条数
self.max_page = 5 # 最大抓取页码
self.secret = "ctrip_mini_program_secret_123" # 模拟secret密钥,实际需逆向获取
self.session = requests.Session() # 维持会话状态
self.ua = UserAgent() # 随机生成UA
self.all_hotel_data: List[Dict] = [] # 存储所有酒店数据
def generate_sign(self, params: Dict) -> str:
"""
生成签名参数(模拟MD5加密逻辑,实际需贴合平台真实算法)
:param params: 核心请求参数
:return: 加密后的签名字符串
"""
# 1. 按平台约定的顺序拼接参数(关键:参数顺序必须与小程序一致)
sign_str = f"{params['cityId']}{params['checkInDate']}{params['checkOutDate']}{params['timestamp']}{self.secret}"
# 2. MD5加密
md5_obj = hashlib.md5()
md5_obj.update(sign_str.encode("utf-8"))
return md5_obj.hexdigest().upper() # 转为大写,贴合多数平台签名格式
def get_request_params(self, page_num: int) -> Dict:
"""
构造完整的请求参数
:param page_num: 页码
:return: 完整请求参数
"""
# 1. 生成毫秒级时间戳
timestamp = int(time.time() * 1000)
# 2. 核心参数(无签名)
core_params = {
"cityId": self.city_id,
"checkInDate": self.check_in_date,
"checkOutDate": self.check_out_date,
"pageNum": page_num,
"pageSize": self.page_size,
"timestamp": timestamp
}
# 3. 生成签名并添加到参数中
core_params["sign"] = self.generate_sign(core_params)
return core_params
def get_request_headers(self) -> Dict:
"""
构造请求头,伪装小程序请求
:return: 请求头字典
"""
return {
"User-Agent": self.ua.random, # 随机UA
"Content-Type": "application/json; charset=utf-8",
"Referer": "https://servicewechat.com/wx1234567890abcdef/0/page-frame.html", # 模拟小程序Referer
"Accept": "application/json, text/plain, */*",
"X-Requested-With": "XMLHttpRequest"
}
def parse_hotel_data(self, response_json: Dict) -> None:
"""
解析响应数据,提取核心酒店信息
:param response_json: 接口返回的JSON数据
"""
try:
# 模拟响应数据结构,实际以抓包的接口响应为准
hotel_list = response_json.get("data", {}).get("hotelList", [])
if not hotel_list:
print("当前页码无酒店数据")
return
# 提取核心字段
for hotel in hotel_list:
hotel_info = {
"hotel_id": hotel.get("hotelId", ""),
"hotel_name": hotel.get("hotelName", ""),
"price": hotel.get("lowestPrice", 0),
"score": hotel.get("hotelScore", 0.0),
"address": hotel.get("address", ""),
"star_rating": hotel.get("starRating", ""),
"check_in_date": self.check_in_date,
"check_out_date": self.check_out_date
```
- 代码关键说明
会话维持:使用requests.Session()维持会话状态,避免每次请求重新建立连接,同时可自动保存 Cookie,适配需要登录验证的接口;
签名生成:模拟 MD5 加密逻辑,实际场景中需通过反编译小程序(如使用 Jadx、Frida 工具)获取真实的签名参数拼接顺序和加密算法;
反反爬策略:使用fake-useragent生成随机 UA,添加time.sleep(2)控制请求频率,避免高频请求触发平台风控,使用高匿代理IP避免引起反爬,例如亿牛云隧道代理
数据存储:使用pandas将数据保存为 CSV 文件,指定encoding="utf-8-sig"防止中文乱码,方便后续数据分析;
异常处理:添加try-except捕获请求异常和数据解析异常,提高爬虫的稳定性。 - 运行结果与后续优化
运行结果:执行代码后,控制台会输出各页码的抓取状态,最终在当前目录生成ctrip_hotel_data.csv文件,包含酒店 ID、名称、价格等核心字段,可直接用 Excel 打开查看;
后续优化方向:
逆向解析真实签名逻辑:使用 FridaHook 小程序的加密函数,获取完整的sign生成算法;
处理加密响应数据:若接口响应为 AES 加密,添加pycryptodome的解密逻辑,解析真实数据;
实现异步抓取:使用aiohttp替代requests,提高多页数据的抓取效率;
增加数据去重:针对hotel_id进行去重,避免重复抓取相同酒店数据;
完善日志记录:使用logging模块替代print,方便排查抓取过程中的问题。
五、总结与风险提示 - 核心总结
本文围绕某程旅行小程序爬虫展开,从技术差异、前期准备、接口分析到实战开发,完整呈现了小程序爬虫的落地流程。核心要点如下:
小程序爬虫的核心在于抓包配置与接口参数解析,尤其是签名等加密参数的模拟;
合规性是爬虫开发的前提,不得触碰平台数据安全与服务器稳定的红线;
反反爬策略的核心是 “伪装” 与 “节制”,模拟正常用户请求,控制请求频率;
实战代码仅为技术演示,实际落地需根据平台接口的真实情况进行调整与优化。