Python 大麦网抢票脚本全解析:从原理到实战(模块化拆解 + 优化指南)
在抢票场景中,手动操作往往难以匹敌抢票工具的响应速度。今天分享一款基于 Python+Selenium 的大麦网抢票脚本,它通过面向对象编程思想,将复杂抢票流程拆分为独立模块,实现了 Cookie 免登录、自动选座、订单提交等核心功能。本文将从模块设计、核心原理、实战注意事项三个维度,带你吃透这款脚本的每一处细节。
一、脚本核心架构总览
脚本整体采用「面向对象 + 模块化」设计,核心逻辑封装在Concert类中,配合全局配置模块和入口函数,形成 “配置→初始化→登录→抢票→收尾” 的完整流程。
整体结构图谱:
大麦网抢票脚本
├── 基础配置模块(库导入+全局常量)
├── 核心类 Concert(抢票主逻辑)
│ ├── Cookie管理模块(免登录核心)
│ ├── 登录模块(登录方式分发+页面初始化)
│ ├── 抢票核心模块(选座+下单)
│ ├── 辅助工具模块(元素判断+资源释放)
└── 入口函数(脚本执行入口)
这种设计的优势在于:单个模块职责单一,便于维护和扩展(比如更换演出、修改登录方式时,仅需调整对应模块)。
二、基础配置模块:脚本运行的 “地基”
基础配置模块负责准备脚本运行所需的依赖库和固定参数,是整个脚本的 “起点”。
1. 依赖库导入及作用
import os # 文件存在性判断、路径处理
import time # 延时控制,模拟人工操作节奏
import pickle # Cookie序列化/反序列化,实现免登录
from time import sleep # 简化延时调用
from selenium import webdriver # 浏览器自动化核心工具
from selenium.webdriver.common.by import By # 元素定位方式枚举
各库的核心作用的:
selenium:核心依赖,负责打开浏览器、定位按钮、模拟点击等所有交互操作;pickle:解决 “重复登录” 问题,将登录后的 Cookie 保存到本地,下次运行直接复用;os:判断 Cookie 文件是否存在,实现 “有 Cookie 免登录,无 Cookie 则手动登录” 的逻辑;time/sleep:避免操作过快导致页面未加载完成,平衡 “抢票速度” 和 “操作稳定性”。
2. 全局常量配置
# 大麦网核心页面URL
damai_url = 'https://www.damai.cn/' # 主页
login_url = 'https://passport.damai.cn/login?ru=https%3A%2F%2Fwww.damai.cn%2F' # 登录页
target_url = '目标演出详情页' # 需抢票的演出页面
常量设计的意义:将高频使用的 URL 固化,后续更换演出时,仅需修改target_url,无需改动核心逻辑,降低维护成本。
三、核心类 Concert:抢票逻辑的 “大脑”
Concert类是脚本的核心,所有抢票操作都围绕这个类的方法展开。类内通过属性控制流程状态,通过方法实现具体功能,逻辑清晰且可复用。
1. 类初始化:初始化核心属性
def __init__(self):
self.status = 0 # 流程状态标记(0=初始化,2=登录成功,3/4/5=不同购票阶段)
self.login_method = 1 # 登录方式(0=模拟登录,1=Cookie免登录)
self.driver = webdriver.Chrome(executable_path='chromedriver.exe') # Chrome驱动对象
self.status:相当于 “流程进度条”,通过状态值控制后续操作(比如只有status=2(登录成功),才能执行选座操作);self.login_method:支持两种登录方式切换,Cookie 免登录是核心优化点,避免重复扫码 / 输入账号密码;self.driver:Chrome 浏览器驱动实例,所有浏览器操作(打开页面、点击按钮等)都通过该对象实现。
四、模块拆解:逐一看懂核心功能
模块 1:Cookie 管理模块(免登录核心)
Cookie 是网站记录用户登录状态的关键数据,该模块通过 “保存 Cookie→读取 Cookie” 的流程,实现免登录功能,是抢票效率的核心保障。
1. set_cookies():首次登录并保存 Cookie
def set_cookies(self):
self.driver.get(damai_url) # 打开大麦主页
print('###请点击登录###')
# 等待用户点击登录按钮(页面标题未变则持续等待)
while self.driver.title.find('大麦网-全球演出赛事官方购票平台') != -1:
sleep(1)
print('###请扫码登录###')
# 等待用户扫码完成(登录成功后页面标题变化)
while self.driver.title != '大麦网-全球演出赛事官方购票平台-100%正品、先付先抢、在线选座!':
sleep(1)
# 保存Cookie到本地文件
pickle.dump(self.driver.get_cookies(), open('cookies.pkl', 'wb'))
print('###cookie保存成功###')
self.driver.get(target_url) # 跳转到抢票页
核心逻辑:
- 手动触发登录:脚本不处理验证码 / 扫码,需要用户手动完成登录操作;
- 状态判断:通过监控页面标题变化,判断登录是否完成(避免代码提前执行);
- 序列化保存:用
pickle.dump()将 Cookie 写入cookies.pkl文件,实现状态持久化。
2. get_cookie():读取 Cookie 实现免登录
def get_cookie(self):
# 读取本地Cookie文件
cookies = pickle.load(open('cookies.pkl', 'rb'))
for cookie in cookies:
# 构造符合要求的Cookie字典(必须指定domain,否则无效)
cookie_dict = {
'domain': '.damai.cn', # 关键:Cookie绑定的域名
'name': cookie.get('name'),
'value': cookie.get('value')
}
self.driver.add_cookie(cookie_dict) # 注入Cookie到浏览器
print('###载入cookie###')
关键注意点:
domain: '.damai.cn'是必填项:Cookie 是域名绑定的,不指定域名会导致 Cookie 注入无效,无法免登录;- 注入时机:需先打开目标页面(
target_url),再注入 Cookie,否则 Cookie 无法生效。
模块 2:登录模块(登录逻辑分发 + 页面初始化)
登录模块负责根据配置的登录方式,完成 “手动登录” 或 “Cookie 免登录”,并初始化抢票页面。
1. login():登录方式分发
def login(self):
if self.login_method == 0:
self.driver.get(login_url) # 直接打开登录页,手动登录
print('###开始登录###')
elif self.login_method == 1:
# 检查Cookie文件是否存在
if not os.path.exists('cookies.pkl'):
self.set_cookies() # 无Cookie则执行首次登录并保存
else:
self.driver.get(target_url) # 有Cookie则直接打开抢票页
self.get_cookie() # 注入Cookie免登录
逻辑分支:
- 方式 0(模拟登录):适用于 Cookie 失效或首次使用的场景,需手动输入账号密码 / 扫码;
- 方式 1(Cookie 免登录):适用于重复抢票场景,直接复用之前的登录状态,节省时间。
2. enter_concert():初始化浏览器 + 登录 + 弹窗处理
def enter_concert(self):
print('###打开浏览器,进入大麦网###')
self.login() # 执行登录
self.driver.refresh() # 刷新页面,使Cookie生效
self.status = 2 # 标记登录成功
print('###登录成功###')
# 关闭登录后的弹窗(通过XPATH定位关闭按钮)
if self.isElementExist('/html/body/div[2]/div[2]/div/div/div[3]/div[2]'):
self.driver.find_element(By.XPATH, '/html/body/div[2]/div[2]/div/div/div[3]/div[2]').click()
额外处理:
- 页面刷新:注入 Cookie 后必须刷新,否则页面无法识别登录状态;
- 弹窗处理:登录后可能出现广告弹窗,通过
isElementExist()判断并关闭,避免弹窗遮挡后续操作。
模块 3:抢票核心模块(选座 + 下单)
这是脚本的核心业务模块,负责监控购票按钮状态、自动选座、提交订单,全程模拟人工抢票流程。
1. choose_ticket():监控购票按钮并触发对应操作
def choose_ticket(self):
if self.status == 2: # 仅登录成功后执行
print('=' * 30)
print('###开始进行日期及票价选择###')
# 未进入订单页面则持续监控
while self.driver.title.find("确认订单") == -1:
try:
buybutton = self.driver.find_element(By.CLASS_NAME, 'buybtn').text
# 根据按钮文本执行不同操作
if buybutton == '提交缺货登记':
# 无票状态,刷新页面重新监控
self.driver.get(target_url)
elif buybutton == '立即预定':
self.driver.find_element(By.CLASS_NAME, 'buybtn').click()
self.status = 3
elif buybutton == '立即购买':
self.driver.find_element(By.CLASS_NAME, 'buybtn').click()
self.status = 4
elif buybutton == '选座购买':
self.driver.find_element(By.CLASS_NAME, 'buybtn').click()
self.status = 5
except:
print('###没有跳转到订单结算界面###')
# 分支处理:选座购买/确认订单
if self.driver.title == '选座购买':
self.choice_seats() # 选座逻辑
elif self.driver.title == '确认订单':
# 提交订单逻辑
while True:
if self.isElementExist('//*[@id="container"]/div/div[9]/button'):
self.check_order()
break
核心逻辑:
- 按钮状态监控:通过循环获取 “购票按钮” 的文本,判断当前票品状态(无票 / 可预定 / 可购买 / 选座购买);
- 分支跳转:根据不同状态触发对应操作,无票时刷新页面重新监控,有票时进入下一步流程。
2. choice_seats():选座购买逻辑
def choice_seats(self):
# 停留在选座页面时持续处理
while self.driver.title == '选座购买':
# 等待用户选座(提示用户手动选座)
while self.isElementExist('//*[@id="app"]/div[2]/div[2]/div[1]/div[2]/img'):
print('请快速选择你想要的座位!!!')
# 选座完成后点击确认按钮
while self.isElementExist('//*[@id="app"]/div[2]/div[2]/div[2]/div'):
self.driver.find_element(By.XPATH, '//*[@id="app"]/div[2]/div[2]/div[2]/button').click()
注意:脚本不支持自动选座(大麦网选座需要人工点击座位区域),此处仅在用户选座后,自动点击 “确认选座” 按钮。
3. check_order():提交订单逻辑
def check_order(self):
if self.status in [3, 4, 5]:
print('###开始确认订单###')
time.sleep(1) # 等待页面加载
try:
# 选中第一个购票人(需提前在大麦网添加购票人信息)
self.driver.find_element(By.XPATH, '//*[@id="container"]/div/div[2]/div[2]/div[1]/div/label').click()
except Exception as e:
print('###购票人信息选中失败, 自行查看元素位置###')
print(e)
# 提交订单(延时0.5秒避免点击无效)
time.sleep(0.5)
self.driver.find_element(By.XPATH, '//*[@id="container"]/div/div[9]/button').click()
time.sleep(20) # 预留支付时间
关键细节:
- 购票人信息:需提前在大麦网绑定购票人(身份证信息),脚本默认选中第一个购票人;
- 延时控制:点击提交订单前延时 0.5 秒,避免页面未加载完成导致点击无效;
- 支付预留:最后延时 20 秒,留给用户在浏览器中完成支付操作。
模块 4:辅助工具模块(元素判断 + 资源释放)
该模块提供通用工具方法,支撑核心模块的稳定运行。
1. isElementExist():判断元素是否存在
def isElementExist(self, element):
flag = True
try:
self.driver.find_element(By.XPATH, element) # 尝试定位元素
return flag
except:
flag = False
return flag
作用:避免因元素未加载(如按钮、弹窗)导致脚本报错崩溃,是脚本稳定性的重要保障(比如判断弹窗是否存在、提交订单按钮是否加载完成)。
2. finish():脚本收尾
def finish(self):
self.driver.quit() # 关闭浏览器,释放资源
作用:抢票完成或出现异常时,关闭浏览器,避免占用系统资源。
五、入口函数:脚本的 “启动开关”
if __name__ == '__main__':
con = Concert() # 实例化抢票类
try:
con.enter_concert() # 初始化浏览器+登录
con.choose_ticket() # 开始抢票
except Exception as e:
print(e) # 打印异常信息
con.finish() # 异常时关闭浏览器
执行流程:实例化Concert类 → 调用enter_concert()完成登录和页面初始化 → 调用choose_ticket()开始抢票 → 捕获异常并关闭浏览器,确保脚本优雅退出。
六、实战注意事项 & 优化建议
1. 实战前准备
- 安装依赖:执行
pip install selenium安装核心库; - Chrome 驱动配置:确保
chromedriver.exe版本与本地 Chrome 浏览器版本一致(或改用webdriver_manager自动适配); - 提前配置:在大麦网添加购票人信息、完成实名认证,避免下单时因信息缺失失败;
- Cookie 有效期:大麦网 Cookie 有效期有限,若免登录失败,删除
cookies.pkl文件后重新运行脚本,手动登录更新 Cookie。
2. 脚本优化方向
- 显式等待替代固定延时:用
WebDriverWait替代sleep(),减少无效等待,提升抢票速度;python
from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 示例:等待购票按钮加载完成(最多等待10秒) WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, 'buybtn'))) - 多线程抢票:通过多线程同时监控多个演出或座位,提升成功率;
- 日志记录:添加
logging模块,记录抢票流程和异常信息,便于排查问题; - 滑动验证处理:若遇到滑动验证,可集成
ddddocr等 OCR 库自动识别滑动缺口(需额外开发)。
七、总结
这款大麦网抢票脚本的核心优势在于 “模块化设计” 和 “Cookie 免登录”,将复杂的抢票流程拆分为独立模块,既便于理解和维护,又能灵活扩展功能。脚本本质是 “模拟人工操作”,无法突破大麦网的防爬机制(如验证码、排队机制),但能通过自动化减少人工操作的延迟,提升抢票成功率

1727

被折叠的 条评论
为什么被折叠?



