ARTICLE DETAIL

资讯详情

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

茅台自动预约系统源码拆解:多账户批量预约与反检测技术详解

茅台自动预约系统源码拆解:多账户批量预约与反检测技术详解 简介这是一套面向Java/Vue全栈开发者与自动化运维实践者的茅台酒预约抢购系统源码聚焦解决官方App抢购成功率低、人工操作耗时费力等痛点适用于个人部署、技术变现或批量账号管理场景。资源包共549个文件涵盖209个Java后端服务模块、87个Vue前端页面组件、84个JS工具脚本、23个XML配置及Dockerfile、Nginx/Redis配置等运维支撑文件整体体积201.6MB结构完整支持本地或云服务器一键部署。已有201人学习下载配套手把手图文搭建教程覆盖从环境准备、多账号注入、门店自动新增内置上千家门店数据到服务启停的全流程。用户可直接基于现有代码二次开发快速构建高并发预约中台并复用bat批处理脚本、.env环境变量配置及SQL初始化脚本等实用工具显著降低部署门槛与调试成本。我拆解了一套“茅台自动预约”项目的全套源码聊聊多账户批量预约系统到底是怎么做出来的做电商自动化和商品预约系统这些年我见过不少“拼手速”的玩法从早期的秒杀脚本到后来的各种预约抢购工具茅台预约绝对算是一个典型场景——商品稀缺、需实名认证、限时限量规则还时不时调整。这类系统的技术栈并不神秘核心就是“批量账户管理 定时调度 自动化请求/操作 风控规避”。这篇文章我会从源码结构和实际业务场景出发把这套系统的设计逻辑、关键模块、部署难点和常见坑一次讲透。不看代码也能理解它做了什么看了源码能更清楚每一步为什么这么设计。老规矩先说结论这套源码并不是一个“点开即用”的黑科技它的价值在于完整展示了如何面向多账户、多平台、高频请求场景设计一套自动化预约系统。里面有账户池、任务队列、验证码识别、IP代理池、浏览器指纹模拟、通知管理等模块虽然代码质量和封装程度残差不齐但整体骨架是健全的适合拿来学习、改造或者在此基础上接入你自己的业务。1. 项目整体设计与思路拆解先别急着看代码先把需求搞清楚。茅台预约这个场景表面上是“到点打开App点一下预约”但真正的难点在于预约窗口期极短通常只有几十秒到几分钟手点根本来不及。一个身份信息只能约一次多账户就意味着需要多套真实身份信息。平台风控会识别设备、IP、行为轨迹、请求频率同一台设备刷多个账号很容易被标记。预约过程有验证码、滑块、文字点选等交互纯模拟请求有时走不通。这套系统解决的就是上述四个问题对应的设计思路如下1.1 多账户与任务队列不要把鸡蛋放在同一个篮子里系统设计了一个账户池的概念。源码中每个账户信息以JSON或数据库记录的形式存储包含平台账号、密码/Token、对应的身份信息、设备指纹标识、独立代理IP、预约目标城市、门店、产品规格等。账户池的核心价值在于隔离。每一条账户数据对应一套独立的“网络身份”和“设备身份”请求时从池中取出一个空闲账户使用它绑定的IP和指纹去发起预约。这与把所有账户都塞在同一IP下相比能显著降低关联风险。代码层面账户池通常由一个AccountManager类管理内含add_account、get_next_available、mark_busy等接口。任务调度模块会循环遍历账户池为每个账户生成预约任务放入队列。队列可以根据业务复杂度选择普通队列按顺序执行或带权重的优先级队列比如把距离较近、成功率较高的门店排在前面。从源码的组织方式看作者使用了多线程 队列的方式实现并发控制而不是把所有账户直接用多线程一股脑跑完。为什么这么设计因为预约平台的接口往往有频率限制如果100个账户同时打一个接口基本等于自爆。队列 信号量限流的模式能在“尽量快”和“尽量稳”之间找一个平衡点这也是真实生产环境中更值得借鉴的处理方式。1.2 反检测的落地方式从IP到指纹再到行为反检测是这套系统中技术含量最高、也是最容易让新手踩坑的部分。对于平台来说它要通过网络请求识别“你是不是真人”。常用的风控维度包括IP信任度同一个IP短时间内请求频率、请求账户数量、历史行为。设备指纹包括User-Agent、浏览器版本、屏幕分辨率、Canvas指纹、WebGL信息、时区、语言等。行为轨迹鼠标移动轨迹、点击停留时间、输入速度以及请求之间的时间间隔分布是否有“机器感”。账户关联图谱同设备、同IP下关联的账户数量手机号绑定关系等。这套源码对应的策略是每个账户绑定一个独立代理IP且IP在每次预约前随机轮换或保留上一轮成功的IP复用。模拟浏览器的请求头时不是写死一组User-Agent而是从指纹池中随机匹配一套完整配置并与账户绑定保持一致。这一点很重要因为如果一个账户一会儿用Chrome 120的UA一会儿用iOS的UA那是明显的异常信号。请求之间的延迟使用动态随机值不是固定sleep几秒而是基于历史平均值加正态分布扰动模拟人工操作。反检测不是“加了代理就安全”而是让每个账户的特征链保持一致、连续避免前后矛盾。这也是很多二级代理脚本容易忽略的细节。1.3 验证码处理一套源码多种方案预约过程中最难绕过的就是验证码。这套源码在这一块做了一个比较聪明的设计多种验证码识别方式并存按场景动态选择。如果验证码是纯数字/字母的四位或六位图使用内置的OCR模型源码集成了tesseract或基于深度学习训练的轻量模型直接识别。如果是滑动验证码则使用缺口识别算法基于OpenCV的边缘检测与模板匹配定位缺口位置再模拟人类拖拽轨迹提交。如果平台风控较强验证码出现频率较高则会切入打码平台接口如某些付费验证码识别服务源码中预留了API key字段填入后即可自动调用。滑块轨迹模拟这一块真要展开讲有不少坑。很多初学的人会卡在“识别缺口容易拖过去却被判定为机器”。核心原因是滑块轨迹太“完美”。真人拖动滑块会有加速、减速、甚至小幅回弹这个源码里用了一个简化的物理模拟模型通过控制位移与时间的关系产生一条类似人类的轨迹曲线。源码中的generate_trace函数接收目标距离和持续时间输出一个(x, y, timestamp)列表内部逻辑是基于Bezier曲线或贝塞尔多段拟合然后加入随机变量。这种方式比直接用线性运动靠谱得多但也不意味着100%能过。能否通过最终还取决于平台风控的阈值设定这个很难拿到确定性的答案只能靠大量样本去调参。2. 核心细节解析与实操要点有了整体思路再看代码里那些容易忽略但影响成败的细节。这部分是拉开普通脚本和“可用系统”之间差距的关键。2.1 预约请求中的关键参数时间戳与签名预约接口最大的特征是“动态化”很多平台都会在请求中带上时间戳和签名参数。签名算法通常在App内或前端JS中需要逆向或抓包分析。这套源码里签名生成模块封装在sign_util.py中。大概是这样的流程取出当前时间戳。将业务参数按字典序排列。拼接一个固定盐值平台每次版本更新可能会更换。进行MD5或HMAC-SHA256哈希。将签名放入HTTP头或请求体中。从源码看到的实现方式签名盐值被硬编码了。这意味着如果平台升级版本换了盐值就需要重新逆向抓取新值否则所有请求都会因签名错误而被拒绝。这种维护成本是无法避免的实际使用时要注意“跟随平台更新”的基本原则。编写代码时建议把盐值、接口路径、关键Header都抽到配置文件中方便更新。另外预约请求中的timestamp参数建议不要直接使用系统当前时间戳而是用“客户端时间与服务器时间的校准偏移量”修正后的值。很多脚本挂掉的原因是本机时钟不准导致请求中的时间戳与服务器时间偏差过大直接被判定为伪造请求。2.2 设备指纹的生成与绑定设备指纹并不是一个单一字段而是一个信息组合。源码里的DeviceProfile对象包含以下字段uaUser-Agent 字符串device_id随机生成的设备唯一标识通常是UUID或特定算法生成的16进制串screen_resolution屏幕分辨率language语言区域timezone时区偏移webgl_vendor、canvas_fingerprint浏览器渲染相关特征生成策略是为每个账户随机生成一套指纹并将指纹与账户绑定存储。之后所有该账户发出的请求都带上这套指纹保持一致性。有一个细节是如果系统检测到当前IP的地理位置与账户常用地点不一致风控可能触发。因此生成指纹时最好与代理IP的国家/地区做匹配不要出现一个美国IP配上中文语言环境的奇怪组合。如果平台端使用了更高级的指纹追踪比如通过canvas渲染生成一个在多个页面间保持一致的ID那么仅靠设置Header是不够的。这种情况下必须使用真实的浏览器环境也就是无头浏览器Headless Browser方案。这套源码提供了两套引擎一种是纯HTTP/HTTPS请求模拟速度快、资源占用小但容易被识别另一种是调用Playwright或Selenium的浏览器自动化模式速度慢但抗检测能力强。两个模式可以在配置文件中切换实际项目里建议对风控较强的平台用浏览器模式对较为宽松的平台用请求模式。2.3 任务调度与并发控制再来看任务调度。源码里核心的调度逻辑位于Scheduler类它维护了一个TaskQueue和多个WorkerThread。关键参数有三个max_workers最大并发线程数。太大会触发平台限制太小又抢不到名额需要根据实际测试调整。经验值单IP下并发不要超过3多IP环境下单线程配对单个IP更安全。本文源码中默认配置是“每3个账户共享一个代理IP每个线程负责1个账户”随着并发数增大IP池需要按比例扩这也是成本的主要来源。retry_times单个任务失败后重试次数。预约接口的重试策略要格外谨慎因为预约本质上是一次性动作成功后重复提交反而可能被判定为异常。源码中逻辑是如果接口返回“预约成功”或“库存不足”则不重试只有出现网络超时或服务端500错误时才重试且每次重试的间隔逐渐增大。task_timeout单个任务总超时时间。预约场景下窗口期可能只有30秒到2分钟所以任务超时不能太久否则后续账户根本来不及跑完。调度逻辑中还有一个容易被忽略的点失败的账户需要打上标记避免下一轮预约再次使用同一套IP/指纹组合。源码中有一个failure_tracker记录失败原因和次数当某个账户连续失败超过阈值后自动冻结防止继续消耗任务时间。2.4 验证码识别与滑块轨迹模拟细节验证码模块是整个源码中代码量最大、依赖最多的部分。我具体说一下滑块识别与轨迹生成的代码逻辑。先看滑块缺口的识别。它是用OpenCV实现的流程是读取背景图和滑块图。将背景图转为灰度图再用Canny边缘检测提取轮廓。用模板匹配方法在背景图中搜索滑块图的相似区域得到缺口的近似位置。基于缺口位置和目标横坐标计算需要拖动的距离。这套方法比较简单直接对于纯色或纹理不复杂的背景图效果还行但碰到复杂背景或滑块图被旋转/加噪的情况识别率会明显下降。更高级的做法包括基于深度学习的语义分割模型如U-Net或者基于Hu矩差异的模板匹配不过需要更多标注数据和计算资源。考虑到源码的使用场景是预约而不是验证码纯对抗本身够用即可。再看轨迹生成。源码中generate_trace函数参考了业界常见的“三段式”轨迹思想第一阶段短暂停顿模拟用户识别验证码并开始移动。第二阶段加速靠近目标但位移不是一次性到位。第三阶段到达目标附近后减速微调对齐然后释放。因为手机端和桌面端的操作习惯不同源码也做了区分手机端滑动距离短、速度快、精度略低桌面端则更平滑、距离长、偶尔有微小回弹。实测下来这种细节划分确实能提高通过率值得借鉴。这块源码还会输出一份轨迹分析数据用来观察不同账户、不同IP段下的滑动行为分布是否过于集中。如果发现某段时间轨迹相似度异常高可以在随机参数上做进一步扰动。3. 实操过程与核心环节实现介绍完原理再走一遍实际部署和使用流程。这里我会用一套模拟环境做演示虽然无法直接对接真实平台出于安全和合规考虑也不建议直接用在实际抢购中但整个流程和配置思路是通用的。3.1 环境准备与依赖安装第一步是准备运行环境。源码是基于Python 3.9开发的依赖库包括requests、playwright、selenium、opencv-python、numpy、pandas、redis用于缓存账户和任务状态等。建议用虚拟环境安装避免污染系统环境。安装命令如下python3 -m venv venv source venv/bin/activate pip install -r requirements.txt其中requirements.txt中列出了项目所有依赖。安装完成后执行python main.py --check可以验证环境是否就绪源码里自带了一个自检模块会检查关键依赖是否安装、代理IP是否连通、OCR引擎是否可用。这一步很贴心能省去大量排障时间。如果走的是浏览器自动化模式还需要执行Playwright的浏览器安装playwright install chromium3.2 配置文件与核心参数解析项目根目录下的config.yaml是核心配置文件字段不少我挑几个关键项来说明mode: playwright # 可选 request 或 playwright headless: true # 无头模式 threads: 3 # 并发线程数 queue_interval: 5 # 每轮任务队列扫描间隔秒 account_pool: - account: user1 password: pass1 id_card: 110101199001011234 city: 北京 store: 旗舰店 proxy: http://127.0.0.1:8888 device_seed: a1b2c3d4e5f6 - account: user2 password: pass2 id_card: 110101199002022345 city: 上海 store: 直营店 proxy: http://127.0.0.1:8889 device_seed: ffaabbccddee scheduler: start_time: 2024-05-01 10:00:00 retry_times: 3 retry_interval: [2, 5, 10] timeout: 30 notify: server_chan_key: smtp_host: smtp_user: smtp_password: receiver: ocr: engine: builtin # builtin / tesseract / cloud api_key: api_secret: 这里有几点需要特别注意threads参数不是越大越好。建议从1开始测试观察成功率、接口响应速度和是否触发风控。稳定后再逐步增加。device_seed是生成设备指纹的随机种子。保持同一账户的种子不变确保指纹长期一致。若平台检测到指纹频繁变化也会被风控。store字段如果平台有门店选择需要提前抓取门店编码填入。源码中提供了store_fetch.py脚本可以自动拉取城市下的门店列表。scheduler.start_time是预约窗口开启时间。调度器会提前几秒启动线程等到时间点则统一发起请求。这里的“统一”不是完全同时而是指每个账户各自基于系统校准时间发起间隔约0.3~1秒有一定随机性。3.3 核心代码逻辑解析现在进入源码中最核心的部分预约主流程。虽然不同平台的接口差异很大但框架结构基本类似。下面是简化后的关键代码def run_reservation(account: Account, config: Config): # 1. 初始化会话 session Session(account.device_seed, account.proxy) # 2. 登录如需要短信验证码则进入等待状态 login_status session.login(account.username, account.password) if not login_status success: return LoginFailed(account) # 3. 获取预约列表与商品信息 product_info session.get_product_info(account.city, account.store) if not product_info.available: return OutOfStock(account) # 4. 提交预约 submit_result session.submit_order( product_idproduct_info.product_id, store_idproduct_info.store_id, id_cardaccount.id_card, ) # 5. 校验结果并通知 if submit_result[status] success: send_notification(f预约成功: {account.username}) return Success(account) else: send_notification(f预约失败: {submit_result[msg]}) return Failed(account)这段流程看似简单真正会写崩的地方往往在第二步和第四步之间的衔接。登录态管理与Cookies持久化是第一个坑。很多平台登录后生成的Cookies有时效性过几分钟就失效。源码中有一个SessionManager会在每次登录后把Cookies序列化保存到Redis中并设置过期时间。下次预约前先尝试复用已有Cookies如果失效再重新登录。这种设计避免了一个会话反复登录导致账号被风控。预约提交不是简单的POST一次就完事有些平台会要求先提交一个预校验请求再走确认流程。源码中submit_order里有pre_check和confirm两个阶段中间间隔一定时间。如果直接跳跃式提交很可能因为缺少状态被拒绝。另外预约成功后还会有一个回查机制即收到“预约成功”响应后再主动查询一次预约记录确认列表中出现了新的预约ID。这一步能防止平台在异步处理时预约状态回滚。3.4 数据存储与通知账户池、任务状态、预约结果这些数据源码默认存储在SQLite中也可以通过配置切换为MySQL或PostgreSQL。多账户场景下数据库设计主要关注三个表accounts存储账户信息、代理IP、指纹种子、状态正常/冻结、失败次数。tasks存储每次预约任务的开始时间、结束时间、结果、错误信息。records存储预约成功的记录包括预约ID、时间、商品信息等。成功/失败的关键事件除了写库还可以通过通知模块即时推送到手机。源码内置了Server酱和SMTP邮件两种通知方式。实际体验中预约结果通知非常重要因为预约窗口短用户需要第一时间决定是否更换门店或补约晚一分钟可能就错过机会。4. 常见问题与排查技巧实录把实际运行中大家问得最多的问题集中整理一下。这一节都是血泪经验。4.1 登录一直提示异常或需要滑块验证怎么办这个问题绝大多数情况不是代码逻辑有误而是“登录行为”太像机器。定位思路按以下顺序排查确认使用的是否为账户绑定的代理IP。如果IP归属地与账户常用地差很远第一次登录就会触发风控。检查设备指纹是否与上次登录时保持一致。在Playwright模式下浏览器指纹是动态生成的如果每次启动都是全新指纹就会被判定为可疑。需要检查device_seed是否固定传入。观察登录前的行为轨迹是否合理。源码中有一个pre_login_simulate函数会在登录前模拟鼠标移动、停留、点击输入框等操作时长约2~5秒。如果这个时间被缩短或跳过登录成功率会下降。如果以上都没问题则可能是平台更新了验证码策略需要对验证码识别模块进行升级或切换为人工介入模式。4.2 预约请求返回“操作频繁”或“系统繁忙”怎么办“操作频繁”是风控系统对高频请求的拦截提示。按照严重程度逐级处理降低threads并发数同时调大queue_interval。这不是妥协而是避免IP被封的主动降级。检查是否所有账户共用了一个代理IP。如果是需要拆分IP池尽量一个IP对应不超过3个账户。检查请求之间的间隔分布是否过于规律。源码会记录每两次请求的时间差如果标准差过小说明间隔太均匀需要调整随机扰动幅度。“系统繁忙”则多半是平台侧限流或临时故障此时不宜硬冲应暂停该账户等10~30秒再试。4.3 滑块缺口识别不准怎么办滑块识别不准的常见场景是背景图带有复杂纹理、干扰元素多或者滑块图片被缩放/旋转。实操中可以调整OpenCV模板匹配的参数降低匹配阈值、扩大搜索区域、对图像做直方图均衡化增强对比度。如果平台滑块每次的缺口样式变化较大就需要考虑打码平台。源码预留了cloud.ocr的接入位填入平台提供的API Key后即可切换。个人项目的权衡是自建识别免费但准确率可能只有70%~85%云平台付费但准确率能做到95%以上。4.4 多账户存在关联风险怎么缓解平台的反作弊不只是看单个请求还会分析账户间的关系。如果100个账户都从同一个IP段注册、同一时间登录、同一时间预约很容易被一锅端。源码中的缓解措施是给账户分批设置不同的时间和频率每个批次的启动时间错开5~30秒而不是到点一起冲。这里有个小心得设置“计划性随机偏移”就是每个账户在预约窗口开启后延迟一个随机秒数发出请求。虽然名义上晚了几秒但能显著降低群体特征。如果代理资源充足更稳妥的做法是每个账户配置一个住宅代理IP并且长期稳定使用频繁更换IP本身就是风险信号。4.5 日志里出现大量超时或连接重置这个问题的根源通常在代理IP的稳定性。测试代理时不要只看连通率还要测握手时间和稳定性。源码中有test_proxy.py脚本会连续发送10次请求并统计响应时间和错误率。建议筛选标准是错误率低于10%平均握手时间小于2秒。如果代理是免费池这种问题几乎无解换质量高一点的代理才能根治。4.6 数据库写入频繁导致任务变慢预约高峰期会产生大量任务状态更新如果在每次请求都同步写库数据库I/O会成为瓶颈。源码的解决方案是引入Redis缓存任务状态先写入Redis再异步批量同步到SQLite/MySQL。实测中这个优化能把任务写入耗时从80ms降低到5ms左右。如果不想引入Redis也可以用内存队列 批量落盘的方式效果类似只是实现上更繁琐。5. 这份源码的局限与优化方向聊完实操也来说说这份源码的不足。它不是一个完美的商业级产品而更像是一个功能齐备但细节粗糙的工程原型。第一代码耦合度高。验证码识别模块和网络请求模块耦合在一起换一种验证码类型就要动核心逻辑。改进方向是将识别模块抽象出统一接口支持插件式注册。第二重试逻辑偏简单。目前的重试策略是固定次数 递增延迟没有考虑“整个任务窗口已过期”的情况。更合理的做法是如果在窗口期内网络错误可以重试业务错误不重试窗口期结束后所有任务强制终止。第三IP池管理比较初级。源码只实现了“账户绑定代理”的静态绑定没有动态切换和健康检查。更成熟的做法是维护IP池的可用队列每次请求前从队列中取一个健康IP请求结束后根据结果回收到不同优先级队列。第四对验证码对抗的鲁棒性不够。内置OCR模型对模糊、扭曲、干扰线强的验证码识别率不高高阶场景必须依赖云服务或人工打码。源码虽然预留了接入位但并没有做自动降级与成本控制。从优化方向上看如果要做成一个真正可用的系统还需要加上用户友好的管理界面用于账户池管理、预约结果统计、通知记录查询以及更完善的风控指标看板。6. 合规使用与实际场景的延伸思考说得再深入一点这类系统的使用边界和合规性也要明确。仅适用于个人合法授权的预约使用。比如你自己有多个家庭成员的身份信息想帮家里人都约上这是合理的授权场景。但未经授权使用他人身份信息进行批量预约就涉嫌违反相关法律和平台规则。在技术层面还有几个方向可以延伸同一套账户池 任务队列的架构也可以用于其他场景比如医院挂号、火车票候补、演唱会门票预约等。核心逻辑大同小异只要替换业务接口和数据解析层即可。这篇文章里的反检测思路也适用于普通爬虫项目的合规改造尤其是“账户维度一致性”和“行为节奏随机化”的部分几乎可以平移到任何需要模拟真实用户的操作中。如果将任务队列替换为分布式消息队列如Celery Redis/RabbitMQ系统就能水平扩展到更大规模的账户池适用于企业级的营销活动自动化。最后还有一件事想提醒源码中所有加解密、签名、指纹相关的代码都在本地运行这意味着一旦你的设备被恶意软件感染账户数据有泄露风险。建议把敏感信息加密存储条件允许的情况下增加远程密钥管理接口不要把明文密码硬编码在配置文件中。7. 实测总结与个人体会如果你只是想要一个“一键抢茅台”的工具这套源码可能还需要大量调优和适配如果你想学习多账户自动化系统的工程设计、风控对抗思路、调度队列与反检测策略的落地方式那它是一个不错的样本。我从这套源码里看到的最有价值的点是作者把“如何从真实需求出发拆解出可落地的技术方案”这个思考过程完整呈现了。账户池怎么设计、IP怎么选、指纹怎么生成、请求间隔怎么控制、失败之后怎么退避这些都是通用方法论放在任何抢购场景下都适用。最后分享一个经验不管代码写得多好真正决定预约成败的往往是最基础的因素——网络质量、代理稳定性和对平台风控规则的理解深度。技术只是放大器基础扎实才是底仓。这套源码里没有写到的部分比如对目标平台版本的持续跟踪能力、对验证码策略的快速应变能力才是拉开差异的真正壁垒。本文还有配套的精品资源点击获取
返回列表