Python自动化预约系统开发:从抓包到多账户并发实战
发布时间:2026/9/3 6:56:06来源:尧图网络
简介这是一套面向Java与前端开发者、自动化运维实践者的茅台App多账户自动预约系统源码专为解决官方渠道抢购难、人工操作效率低等痛点而设计适用于个人部署、技术学习或小规模商用场景。资源包共556个文件涵盖209个Java后端核心逻辑、87个Vue前端页面、84个JS交互脚本、92个SVG图标资源以及Dockerfile、Nginx与Redis配置文件等运维支撑组件整体体积201.61MB结构完整、模块清晰支持快速本地调试与云服务器一键部署。已有359人学习下载配套提供手把手MP4视频搭建教程覆盖环境配置、账号导入、门店自动新增内置上千家门店数据、服务启停等全流程新手可零基础完成从解压到上线的全部操作。1. 项目背景与核心需求解析最近几年一些热门商品的线上预约抢购比如“i茅台”APP上的茅台酒已经成了一场技术与人力的较量。手动操作不仅耗时耗力成功率还极低尤其是在面对服务器高并发、网络延迟和验证码等多重挑战时。因此围绕这类APP的自动化预约、抢购程序成为了一个非常具体且现实的技术需求。这个项目就是一套针对“i茅台”这类APP的多账户自动预约程序系统源码。这套源码的价值远不止于“能抢茅台”。它本质上是一个研究移动端APP自动化交互、网络请求模拟、多任务并发调度以及风控对抗的综合性技术实践案例。对于开发者而言它提供了一个绝佳的窗口去理解现代APP特别是带有强安全策略的金融、电商类APP其前后端是如何通信的数据是如何加密的以及自动化脚本如何尽可能地模拟真人行为以绕过检测。很多朋友可能从“大麦网抢票脚本”、“电商秒杀脚本”等关键词里找到这里其底层逻辑是相通的都是对特定APP或网站业务流程的自动化复现。那么这套源码具体解决了什么问题呢核心就是三个字自动化和规模化。它允许你配置多个预约账户即“多账户”由程序自动完成登录、获取商品信息、提交预约订单等一系列操作解放双手并理论上通过并发提升成功率。它不是一个简单的“按键精灵”录屏脚本而是通过分析APP的网络请求即常说的“抓包”直接模拟协议层的交互效率更高也更隐蔽。项目提供的“带视频搭建教程”则是为了降低技术门槛让有一定基础但非资深的开发者也能跑起来看到效果。2. 技术栈与核心原理拆解要理解这套系统是如何工作的我们需要深入到它的技术实现层面。这不仅仅是用Python写几个requests那么简单它涉及移动端逆向、协议分析、调度策略等多个环节。2.1 核心工作流程从抓包到模拟请求整个系统的运行遵循一个清晰的链路环境准备 - 数据捕获 - 协议分析 - 请求模拟 - 任务调度。首先你需要在一个可控的环境里运行目标APP比如安卓模拟器如MuMu、夜神或真机并配置好抓包工具如Fiddler、Charles或mitmproxy。这一步的目的是为了捕获APP与服务器之间所有的网络通信数据。当你手动在APP上完成一次完整的预约流程时抓包工具会记录下所有的HTTP/HTTPS请求和响应。接下来是最关键也最耗时的部分协议分析。你需要从海量的请求中筛选出与登录、获取商品列表、提交预约等核心功能相关的接口。然后逐一分析每个请求URL与参数接口地址是什么提交了哪些参数哪些是固定的哪些是动态变化的如时间戳、Token、商品ID请求头Headers除了常见的User-Agent、Content-Type通常还会有一些APP自定义的头部比如设备标识、签名、版本号、Token等。这些往往是风控的关键。数据格式与加密POST提交的数据是JSON还是表单数据内容是否被加密常见的加密方式有Base64、AES、RSA或者是自定义的混淆算法。你需要通过逆向工程使用JADX-GUI、Frida等工具分析APP源码或黑盒测试对比不同请求的差异来推断加密逻辑。签名验证Sign这是最高级别的风控。服务器会要求客户端对请求的某些部分如所有参数按特定规则排序后拼接再加上一个密钥进行哈希计算如MD5、SHA256将结果作为sign参数提交。服务器用同样的算法验证不一致则拒绝请求。破解签名是自动化脚本最大的难点。分析清楚后就可以用Python或其他语言的requests库按照分析出的规则构造出完全一样的HTTP请求实现自动化。这就是“抓包”和“逆向”在自动化中的核心应用。2.2 多账户与并发调度策略单个账户的自动化只是基础系统的威力在于“多账户”。这不仅仅是简单地在代码里写多个用户名密码循环执行。账户管理模块需要设计一个灵活的结构来存储账户信息账号、密码、实名信息、收货地址等通常会用JSON或YAML配置文件或者一个小型数据库如SQLite。每个账户应该是一个独立的对象持有自己的会话Session、Token等状态信息避免相互干扰。并发与调度策略是提升成功率的关键。粗暴地同时发起大量请求极易触发服务器的频率限制或封禁。因此需要更精细的策略时间分散为每个账户的请求加入随机延迟如0.5秒到3秒之间模拟真人操作的间隔。队列与优先级可以设计一个任务队列根据商品热度、账户等级等设定优先级。协程与异步IO使用asyncio、aiohttp等库进行异步请求可以在单线程内高效管理上百个账户的连接避免多线程/进程的沉重开销。这是目前高性能爬虫和自动化工具的标配。代理IP池为了防止单个IP请求过多被屏蔽需要集成代理IP池为不同的账户或请求分配不同的IP地址。IP的质量稳定性、速度、匿名度直接决定程序的存活时间。2.3 风控对抗与行为模拟一个只能运行几分钟就被封的脚本是没用的。因此系统必须考虑对抗APP和服务器端的反自动化检测。设备指纹模拟APP通常会收集设备信息如型号、系统版本、屏幕分辨率、IMEI/Android ID等生成一个设备指纹。脚本需要能伪造或复用一套合理的设备信息。请求链完整性有些操作需要前置的请求来获取关键参数如一个token来自上一个请求的响应。脚本必须完整地模拟这个链条不能跳步。行为轨迹模拟高级风控会分析用户的行为序列和间隔。脚本可以在关键步骤间加入符合人类操作习惯的等待和“假动作”如模拟滑动屏幕、点击无关区域再返回。验证码处理如果遇到图形验证码需要集成打码平台如超级鹰、图鉴的API进行识别。更复杂的滑动验证码或点选验证码则可能需要更复杂的图像识别或机器学习方案。签名算法保持更新这是持续的攻防战。APP更新后签名算法很可能改变。脚本需要易于维护能够快速定位和更新加密、签名相关的代码模块。3. 系统源码结构与环境搭建实战理解了原理我们来看如何把这份源码运行起来。一个结构清晰的源码项目是后续所有开发和维护的基础。3.1 项目目录结构与模块解析一个典型的自动化预约系统源码目录可能如下所示根据实际项目会有调整iMaoTai_Auto/ ├── config/ # 配置文件目录 │ ├── accounts.yaml # 账户配置文件 │ ├── settings.yaml # 全局设置请求间隔、代理开关等 │ └── products.yaml # 目标商品配置 ├── core/ # 核心逻辑模块 │ ├── __init__.py │ ├── fetcher.py # 数据抓取模块负责请求网页/API │ ├── parser.py # 数据解析模块解析响应内容 │ ├── scheduler.py # 任务调度器管理多账户和定时 │ ├── simulator.py # 行为模拟模块处理加密、签名 │ └── notifier.py # 通知模块邮件、微信、钉钉 ├── utils/ # 工具函数 │ ├── __init__.py │ ├── logger.py # 日志记录 │ ├── encrypt.py # 加密解密工具 │ ├── network.py # 网络请求工具封装代理、重试 │ └── captcha.py # 验证码处理 ├── drivers/ # 浏览器驱动或设备驱动 │ └── chromedriver.exe (或其他) ├── logs/ # 日志文件目录运行时生成 ├── requirements.txt # Python依赖包列表 ├── main.py # 主程序入口 └── README.md # 项目说明文档config/这是项目的“控制中心”。accounts.yaml里明文或加密存储你的账户信息切记不要将此文件上传到Git等公开仓库。settings.yaml控制程序行为如总开关、请求延迟、重试次数、是否开启代理等。core/这是大脑。fetcher和parser负责与外界通信和理解信息。scheduler是指挥官决定哪个账户在什么时候做什么。simulator是技术专家负责生成那些让服务器信以为真的加密参数和签名。notifier是你的信使成功或失败时第一时间通知你。utils/工具包。良好的日志logger是调试和监控的命脉必须记录下每个关键步骤和发生的错误。network模块应该统一管理请求内置超时、重试、代理切换和简单的异常处理机制。requirements.txt列出了所有必需的Python库如requests,aiohttp,pyyaml,schedule,cryptography等。使用pip install -r requirements.txt可以一键安装。3.2 关键依赖安装与环境配置根据视频教程和requirements.txt搭建环境的步骤通常如下安装Python确保你的电脑安装了Python 3.7或以上版本。建议使用pyenv或conda创建独立的虚拟环境避免污染系统环境。# 创建虚拟环境以conda为例 conda create -n imaotai_auto python3.8 conda activate imaotai_auto安装依赖进入项目根目录安装所有依赖包。pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple如果遇到某些包安装失败可能是版本冲突或系统依赖缺失需要根据错误信息单独解决。配置抓包环境这是获取最新接口数据的前提。以Fiddler为例安装Fiddler Classic。设置Fiddler允许解密HTTPS流量Tools - Options - HTTPS。在连接设置中允许远程计算机连接Connections选项卡。在手机或模拟器上设置Wi-Fi代理为电脑的IP地址和Fiddler的端口默认8888。在手机浏览器访问http://电脑IP:8888下载并安装Fiddler的根证书。启动“i茅台”APP进行操作Fiddler中就能看到捕获的请求。逆向分析工具准备可选但重要对于复杂的加密可能需要静态或动态分析APP。静态分析使用JADX-GUI打开APP的APK文件可以查看反编译后的Java代码搜索关键词如“encrypt”、“sign”、“md5”、“AES”等。动态分析使用Frida框架可以在APP运行时注入代码Hook关键函数直接打印出输入参数和返回值是破解签名算法的利器。但这需要一定的移动安全逆向基础。3.3 配置文件详解与账户管理配置文件是程序与用户交互的界面设计得好不好用直接影响体验。accounts.yaml示例accounts: - username: 13800138000 password: your_encrypted_password # 建议使用加密后的密码 real_name: 张三 id_card: 110101199001011234 token: # 通常由登录后获取初始为空 enabled: true priority: 1 - username: 13900139000 password: another_encrypted_pwd real_name: 李四 id_card: 110101199002022345 token: enabled: true priority: 2重要提示密码明文存储是极度危险的。一种简单的改进方式是使用对称加密如AES对密码进行加密在代码中读取时再解密。密钥可以放在环境变量中而不是配置文件里。settings.yaml示例global: request_timeout: 10 max_retries: 3 retry_delay: 2 random_delay_range: [0.5, 2.0] # 请求间随机延迟秒数 enable_proxy: false proxy_pool_url: http://your-proxy-pool.com/get # 如果启用代理 notification: enable: true type: serverchan # 可选serverchan微信、dingtalk、email serverchan_key: your_sckey dingtalk_webhook: your_webhook_url schedule: cron: 0 9 * * * # 每天上午9点执行使用cron表达式 enable_random_start: true # 在定时点前后随机几分钟启动products.yaml示例products: - product_id: 1001 product_name: 飞天茅台 53%vol 500ml shop_ids: [shop_001, shop_002] # 意向门店ID列表 enabled: true配置完成后主程序main.py会读取这些配置初始化账户对象池、任务调度器然后按照设定的时间或立即开始执行预约流程。4. 核心功能模块的代码实现与调试有了清晰的架构和配置我们深入到几个核心模块的代码层面看看具体如何实现。4.1 网络请求模块健壮性与伪装一个健壮的网络请求模块是脚本的基石。它不能只是一个简单的requests.get包装。# utils/network.py import requests import time import random from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry from .logger import get_logger logger get_logger(__name__) class RequestClient: def __init__(self, use_proxyFalse, proxy_pool_urlNone): self.session requests.Session() # 设置重试策略 retry_strategy Retry( total3, # 总重试次数 backoff_factor1, # 重试等待时间增长因子 status_forcelist[429, 500, 502, 503, 504], # 遇到这些状态码重试 allowed_methods[HEAD, GET, POST, PUT, DELETE, OPTIONS, TRACE] ) adapter HTTPAdapter(max_retriesretry_strategy) self.session.mount(http://, adapter) self.session.mount(https://, adapter) # 设置通用请求头模拟常见浏览器 self.session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: application/json, text/plain, */*, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Connection: keep-alive, }) self.use_proxy use_proxy self.proxy_pool_url proxy_pool_url self.current_proxy None def _get_proxy(self): 从代理池获取一个代理IP if not self.use_proxy or not self.proxy_pool_url: return None try: resp requests.get(self.proxy_pool_url, timeout5) if resp.status_code 200: proxy_ip resp.text.strip() self.current_proxy {http: fhttp://{proxy_ip}, https: fhttp://{proxy_ip}} logger.info(f获取到新代理: {proxy_ip}) return self.current_proxy except Exception as e: logger.error(f获取代理失败: {e}) return None def request(self, method, url, **kwargs): 统一的请求方法内置代理、重试和日志 proxies self._get_proxy() if self.use_proxy else None # 加入随机延迟模拟人工操作 delay random.uniform(0.5, 2.0) time.sleep(delay) try: response self.session.request(method, url, proxiesproxies, **kwargs) response.raise_for_status() # 如果状态码不是200抛出HTTPError异常 logger.debug(f请求成功: {method} {url} - 状态码: {response.status_code}) return response except requests.exceptions.RequestException as e: logger.error(f请求失败: {method} {url} - 错误: {e}) # 这里可以加入更复杂的错误处理比如切换代理、账户等 raise这个RequestClient类封装了会话保持、自动重试、代理切换和基础日志是其他模块发起网络请求的基础。4.2 登录与会话维持对于需要登录的APP维持一个有效的会话Session至关重要。登录过程通常是破解的第一个难点。# core/simulator.py (部分) import hashlib import time import json from utils.encrypt import some_encrypt_function # 假设的加密函数 from utils.network import RequestClient class LoginSimulator: def __init__(self, account): self.account account self.client RequestClient() # 从抓包数据中提取的固定URL和头部 self.login_url https://app.moutai.com/api/v1/login self.headers { Host: app.moutai.com, App-Version: 2.5.0, Device-ID: 模拟生成的设备ID, Content-Type: application/json;charsetUTF-8, # ... 其他必要头部 } def _generate_sign(self, params): 模拟签名生成算法示例实际需逆向分析 # 1. 将参数按Key排序后拼接成字符串 sorted_params .join([f{k}{params[k]} for k in sorted(params.keys())]) # 2. 拼接上密钥这个密钥需要从APP中逆向得到 secret 逆向得到的密钥 sign_string sorted_params secret # 3. 计算MD5也可能是其他哈希算法 sign hashlib.md5(sign_string.encode(utf-8)).hexdigest() return sign def login(self): 执行登录获取并更新账户的token # 构造登录参数密码可能需要先加密 timestamp int(time.time() * 1000) login_params { mobile: self.account.username, password: some_encrypt_function(self.account.password), # 密码加密 timestamp: timestamp, nonce: 随机字符串, } # 生成签名 login_params[sign] self._generate_sign(login_params) # 发送登录请求 try: response self.client.request(POST, self.login_url, jsonlogin_params, headersself.headers) data response.json() if data.get(code) 200: # 假设成功码是200 self.account.token data[data][token] self.account.session_id response.cookies.get(SESSIONID) # 更新client的session headers后续请求携带token self.client.session.headers.update({Authorization: fBearer {self.account.token}}) return True else: logger.error(f登录失败: {data.get(message)}) return False except Exception as e: logger.error(f登录请求异常: {e}) return False登录成功后获取到的token和cookies需要妥善保存并在后续的所有请求中携带以维持登录状态。通常token会放在请求头Authorization中。4.3 预约任务执行与并发控制这是系统的核心执行单元。我们使用asyncio和aiohttp来实现高效的异步并发。# core/scheduler.py import asyncio import aiohttp import random from datetime import datetime from .simulator import LoginSimulator from .notifier import Notifier from utils.logger import get_logger logger get_logger(__name__) class Scheduler: def __init__(self, accounts, products): self.accounts accounts self.products products self.notifier Notifier() self.semaphore asyncio.Semaphore(5) # 控制最大并发数避免被封 async def _reserve_for_account(self, account, product, session): 单个账户对单个商品的预约任务 async with self.semaphore: # 控制并发 # 1. 确保登录态有效这里简化实际可能需要定期刷新token if not account.token: simulator LoginSimulator(account) if not simulator.login(): logger.error(f账户 {account.username} 登录失败跳过) return False # 2. 构造预约请求 reserve_url https://app.moutai.com/api/v1/reserve reserve_data { product_id: product.product_id, shop_id: random.choice(product.shop_ids), # 随机选择一个门店 count: 1, timestamp: int(datetime.now().timestamp() * 1000), } # ... 此处应有生成签名的逻辑 headers { Authorization: fBearer {account.token}, # ... 其他必要头部 } # 3. 发送异步请求 try: async with session.post(reserve_url, jsonreserve_data, headersheaders) as resp: result await resp.json() if result.get(code) 200: logger.info(f账户 {account.username} 预约 {product.product_name} 成功) # 发送成功通知 await self.notifier.send(f预约成功提醒, f账户{account.username}\n商品{product.product_name}) return True else: logger.warning(f账户 {account.username} 预约失败: {result.get(message)}) return False except Exception as e: logger.error(f账户 {account.username} 请求异常: {e}) return False async def run(self): 主调度运行方法 logger.info(开始执行多账户预约任务...) async with aiohttp.ClientSession() as session: tasks [] for account in self.accounts: if not account.enabled: continue for product in self.products: if not product.enabled: continue # 为每个账户-商品组合创建一个异步任务 task self._reserve_for_account(account, product, session) tasks.append(task) # 等待所有任务完成 results await asyncio.gather(*tasks, return_exceptionsTrue) success_count sum(1 for r in results if r is True) logger.info(f任务执行完毕。成功: {success_count}, 失败: {len(results)-success_count})这个调度器会为每个有效的账户和商品的组合创建一个异步任务并通过信号量Semaphore控制全局并发数避免对服务器造成过大压力。所有任务同时发起但受信号量限制同一时间只有固定数量的请求在真正执行。5. 常见问题排查与进阶优化即使代码跑起来了在实际运行中也会遇到各种各样的问题。这里分享一些典型的踩坑经验和优化思路。5.1 请求失败与风控拦截的排查链路当你的脚本突然全部请求失败或者返回一些奇怪的错误码时不要慌按照以下链路排查检查网络与基础环境你的电脑能正常上网吗模拟器或代理的网络通畅吗抓包工具还在运行吗证书安装是否依然有效HTTPS抓包失败最常见运行ping app.moutai.com看看域名解析和基本连通性。检查账户与Token状态手动用手机APP登录一下你的账户看是否被限制或需要验证。检查脚本中使用的token是否过期。Token通常有有效期如2小时、1天过期后需要重新登录。在代码中加入Token过期的判断和自动刷新逻辑。在请求中打印出当前的token和关键请求头与抓包到的正常请求进行对比看是否有遗漏或错误。分析请求与响应开启详细的日志打印出每次请求的URL、请求头、请求体注意脱敏和完整的响应内容。对比失败请求和成功请求可能是之前抓包保存的的每一个细节。重点关注URL是否完全一致有没有多或少参数请求头User-Agent,Content-Type,Authorization, 以及所有自定义头部如X-Sign,X-Timestamp的值是否正确。请求体JSON的字段名、字段顺序、数据类型字符串还是数字是否一致时间戳是否在有效范围内签名这是重中之重。重新计算一遍签名看是否和发送出去的一致。检查签名算法依赖的参数是否都正确包含并排序了。识别风控特征如果返回“操作过于频繁”、“请稍后再试”说明触发了频率限制。需要增加请求间隔或者使用更优质的代理IP池分散流量。如果返回“验证码错误”或直接弹出图形验证码说明该账户或IP的行为已被标记为可疑。需要集成打码平台或者更换IP、暂停该账户一段时间。如果返回“系统繁忙”、“服务器错误”可能是服务器本身问题也可能是你的请求格式有误导致服务器无法处理。用抓包工具抓一次当前时间的手动成功请求进行比对。如果直接返回403 Forbidden或400 Bad Request很可能是签名错误或缺少必要参数。使用调试工具对比工具使用Beyond Compare或在线JSON对比工具仔细比对请求差异。重放攻击在抓包工具如Fiddler中找到一个成功的历史请求直接右键“Replay”或“Compose”重放看是否能成功。如果能说明问题在你的请求构造上如果不能说明服务器端状态已变如商品下架、活动结束。5.2 性能优化与稳定性提升一个能长期稳定运行的脚本才是好脚本。异步IO的深度优化asyncio虽然高效但不当使用也会导致问题。确保使用aiohttp.ClientSession作为全局会话而不是为每个请求创建新的。合理设置连接池限制和超时时间。connector aiohttp.TCPConnector(limit30, limit_per_host5) # 限制总连接数和每主机连接数 timeout aiohttp.ClientTimeout(total15) # 总超时15秒 async with aiohttp.ClientSession(connectorconnector, timeouttimeout) as session: # 使用这个session进行所有请求代理IP池的质量管理免费的代理IP大多不稳定。投资一个付费的优质代理IP服务是值得的。在代码中需要对代理IP进行有效性检测访问一个测试网站并建立淘汰和补充机制。完善的日志与监控日志不仅要记录成功失败还要记录关键步骤的耗时、使用的代理IP、返回的数据片段等。这有助于事后分析性能瓶颈和问题原因。可以考虑将日志同时输出到文件和像Sentry这样的错误监控平台。配置的热重载不要每次修改配置都重启程序。可以设计一个信号监听机制比如监听配置文件修改时间实现配置的热更新。优雅降级与熔断当连续多次请求失败或某个接口返回特定错误码时应触发“熔断”暂停对该接口或目标地址的请求一段时间避免在无效请求上浪费资源和触发更严厉的风控。5.3 法律与道德风险规避这是所有类似项目必须严肃对待的底线。遵守用户协议几乎所有APP的用户协议都明确禁止自动化脚本、机器人等非人工操作。使用此类脚本存在账号被封禁、权益被清零的风险。你需要明确知晓并自行承担此风险。拒绝黄牛与牟利本技术分享仅供学习和研究自动化技术之用理解网络协议和反爬机制。坚决反对将其用于囤积居奇、扰乱市场秩序的黄牛行为。技术的价值在于创造和提升效率而非破坏公平。控制请求频率在代码中务必设置合理的请求间隔和并发数避免对目标服务器造成拒绝服务攻击DoS级别的压力。这不仅是不道德的也可能构成违法行为。数据隐私脚本处理了你的个人账户信息。务必确保你的源码、配置文件尤其是含有密码的存储安全不要泄露给他人。技术的边界在于使用它的人。保持对技术的敬畏将其用于正当的学习和效率提升才是长久之道。这套源码提供了一个绝佳的学习框架但每一个将其投入实际运行的人都必须面对随之而来的技术挑战和潜在风险。本文还有配套的精品资源点击获取
网站建设高端定制企业官网