Python+Selenium抢票脚本实战:从零搭建浏览器自动化购票工具

发布时间:2026/9/20 6:26:49
Python+Selenium抢票脚本实战:从零搭建浏览器自动化购票工具 先说明白这个所谓的“抢票神器”本质上就是一个用 Python 写的浏览器自动化脚本。它不改票务平台的任何规则也不绕过支付环节核心工作就是代替人手去完成三件事持续盯着票务页面的状态变化在可购买的第一时间点下按钮然后尽可能快地选好票档、确认观影人并提交订单。如果你和我一样只是想提高购票流程里的操作效率这个脚本确实能帮上忙但如果你指望它突破限购规则、抢到根本没有放出的票那我建议趁早放弃这个念头。这篇文章是我自己从零开始写抢票脚本的完整记录。前后改了好几版踩过不少坑实际抢票也翻过车。今天把完整的使用流程、关键技术点和实测遇到的问题都整理出来给想用 Python 自动化解决实际抢票问题的朋友做个参考也适合想练手 Selenium 的 Python 初学者跟着过一遍。环境上用 Windows 或者 macOS 都可以整个项目核心依赖只有两个Selenium 库和对应的浏览器驱动。1. 拆解“抢票”背后的技术逻辑一上来就写代码肯定是不行的先把思路理清楚。抢票这件事本质上是把“限时操作”和“并发竞争”两个问题叠加在一起。你面对的不是一个静态页面而是一个会在某个精确时间点从“缺货登记”变成“立即购买”的动态页面。人自己去抢输在三个地方反应速度不稳定、手速有上限、长时间盯着页面会疲劳。而脚本是确定性程序只要页面结构没有大改它的点击速度、判断逻辑和执行节奏都是一致的而且可以连续运行几小时不休息。明白了这个前提下一步是选实现方案。我在网上看到同行们常用的做法大概有三类各有各的优劣方案原理优点致命缺陷按键精灵类GUI自动化录制鼠标键盘操作循环重放上手最快完全不用写代码页面结构一变动就全废无法感知当前页面状态容易点错直接抓HTTPS接口用Python模拟浏览器发送购票请求速度最快可以并发需要逆向前端JS处理签名、加密参数难度高且容易过界Python Selenium用代码操控真实浏览器模拟真人操作不需要破解接口逻辑能看到真实页面反馈速度不如接口直调但应对个人抢票足够我最终选了 Python Selenium核心原因是它在“实现难度”和“可控性”之间取得了最好的平衡。你不用去逆向分析加密参数只需要像人一样操作浏览器就行同时因为每一步操作都能实时看到页面反馈调试起来要直观得多。现在的 Python 生态里其实还有 Playwright、Pyppeteer 这类更现代的自动化框架功能更强但为了搞定一个“定时点击 表单提交”的需求Selenium 完全够用而且网上踩坑资料多遇到问题了也更容易找到解决方案。这里我想多说一句我建议把抢票脚本当成一个自动化技术学习项目来玩别把它定位成所谓的“外挂”。心态对了你学到的是 Selenium 元素定位、页面等待、cookies 管理这些通用技能这些技能换到任何 Web 自动化场景都能复用心态偏了你就会总想着怎么去对抗平台风控最后很容易翻车。1.1 为什么不用“sleep定时”这种笨办法很多第一次写抢票脚本的人第一个想法是我在本地算好时间到点了让程序立刻点按钮。这个思路听起来简单实际却有个隐患你本地电脑的系统时间和目标服务器的标准时间通常会存在偏差可能差几秒也可能差几十秒。你提前一秒点了按钮还没生效你晚点了一秒热门场次的票可能已经被“秒没”。正确思路是让脚本早点打开页面然后持续监听页面上的倒计时文本或者持续等待按钮状态从“不可点击”变为“可点击”一旦状态变化就立刻执行点击。这种“事件驱动”的方式以服务器返回的页面状态为准不受本地时钟偏差影响。这也是整套脚本里最核心的一个设计点。1.2 脚本到底能做什么、不能做什么再明确一下边界。这个脚本能做的事自动登录、自动刷新票务状态、自动点击购买按钮、自动选票档、自动预填观影人信息并提交订单。它不能做的事突破平台风控、绕过限购规则、伪造身份信息、在无票的情况下凭空出票。在我自己的使用体会里脚本最大的价值不是“保证抢到”而是“稳定地帮你完成重复操作”。尤其是选观影人、同意购票协议、提交订单这几步正常人手点怎么也要几秒钟脚本在页面不卡的情况下几百毫秒就能完成。对热门演出来说这几百毫秒的差距确实有可能决定成败。2. 环境准备与基础工具搭建工欲善其事必先利其器。在写抢票逻辑之前先把 Python 环境、Selenium 库和浏览器驱动这三样东西装好。每一步都不难但版本匹配问题很容易在事后给你添堵所以我单独把环境搭建写一章。2.1 Python 环境安装如果你电脑上已经装过 Python直接在终端里输入python --version确认一下版本3.8 及以上都可以。如果没装去 Python 官网下载对应操作系统的安装包即可。Windows 用户安装时有一个地方特别提醒安装向导第一页一定要勾选Add Python to PATH这个选项默认是不勾的不勾会导致后面在命令行里执行python命令时提示“python was not found”。装完以后按Win R输入cmd打开命令提示符输入python --version能正常输出版本号就说明安装成功了。macOS 用户直接下载官方安装包安装安装完在“终端”里执行python3 --version验证。另外macOS 自带的 Python 版本通常比较老建议优先使用官网最新稳定版。还有一个提升下载速度的小技巧Python 的第三方库默认从海外源下载国内网络环境下可能会很慢。安装库时可以用国内镜像源比如清华源pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple这个参数只是临时指定下载源不会影响后续库的使用。2.2 安装 Selenium 与浏览器驱动Selenium 库本身安装很简单一行命令的事。比较麻烦的是浏览器驱动也就是让 Python 能够“指挥”浏览器的中间层。这里以 Chrome 浏览器为例。你需要先确认自己 Chrome 的版本号在地址栏输入chrome://version记下版本号的第一位然后去 ChromeDriver 官方下载地址选择相同或接近的版本下载。版本匹配是一条铁律Chrome 大版本是 126Driver 就必须是 126 系列不匹配的时候浏览器会直接拒绝启动报错内容通常是session not created或者This version of ChromeDriver only supports Chrome version xx。Windows 用户下载解压后得到一个chromedriver.exe建议直接放到和脚本相同的目录下后面代码里就不用写绝对路径了。macOS 用户同样下载对应版本放到/usr/local/bin目录下或者直接把路径写进代码。新版 Selenium 4.6 之后自带了一个 Selenium Manager理论上会帮你自动匹配并下载驱动实测下来能省不少事。但国内网络环境下偶尔会下载失败所以手动下载驱动仍然是最稳妥的办法。我个人的建议是优先让 Selenium Manager 试一次不行就手动配两条路都掌握才算真的稳。2.3 环境测试装完之后先跑一个最小的测试确认整条链路是通的from selenium import webdriver options webdriver.ChromeOptions() options.add_experimental_option(excludeSwitches, [enable-automation]) driver webdriver.Chrome(optionsoptions) driver.get(https://www.damai.cn) print(driver.title) driver.quit()能正常打开页面并打印出标题就说明 Selenium 和驱动的链路没问题。这里有一个经验第一次跑的时候不要加太多“伪装”参数先把基本链路跑通再考虑后续优化。很多人一上来就复制网上那一套--disable-blink-featuresAutomationControlled、--user-agent之类的参数结果环境没通问题反而复杂化了。3. 核心实现一个可用的抢票脚本环境准备好了接下来是重头戏实现抢票核心逻辑。我把它拆成了三个模块登录态保持、抢票主流程、关键参数调优。这三个模块分别解决“不用每次扫码”“第一时间点到按钮”“提交订单不卡壳”的问题。3.1 登录态保持把 cookies 存成本地文件大麦网在下单前会校验登录态所以脚本第一步必须是已登录状态。每次运行脚本都扫码登录会很烦而且扫码那几秒钟可能正好错过开票时间。解决办法是第一次手动扫码登录然后把登录后的 cookies 保存到本地 JSON 文件后续启动脚本时直接加载。import json import time from selenium import webdriver def login_and_save_cookies(driver, cookie_pathdamai_cookies.json): 第一次运行手动扫码登录保存cookies driver.get(https://passport.damai.cn/login?returnUrlhttps://www.damai.cn/) input(请在浏览器中完成扫码登录登录成功后回到终端按回车...) cookies driver.get_cookies() with open(cookie_path, w, encodingutf-8) as f: json.dump(cookies, f, ensure_asciiFalse, indent2) print(cookies 保存成功) def load_cookies(driver, cookie_pathdamai_cookies.json): 后续运行加载本地cookies维持登录态 with open(cookie_path, r, encodingutf-8) as f: cookies json.load(f) driver.get(https://www.damai.cn/) for cookie in cookies: if expiry in cookie: del cookie[expiry] driver.add_cookie(cookie) driver.refresh()这段代码里有两个容易踩坑的细节。第一add_cookie之前必须先打开目标域名下的页面否则浏览器会报 “cannot create cookie” 错误。第二Selenium 在读取 cookies 时会返回expiry字段这个字段是时间戳格式直接调用add_cookie加回去偶尔会因为格式问题报错所以在写入前把它删掉比较省心。实际操作中cookies 是有有效期的可能几个小时也可能几天。如果脚本运行时报“请重新登录”的错误多半就是 cookies 过期了重新执行一次login_and_save_cookies就好。3.2 抢票主流程监测状态并自动提交抢票主流程是脚本的心脏我按步骤拆开写打开目标演出详情页循环刷新页面等待购买按钮从不可点击变为可点击点击“立即购买”或“选座购买”选择票档和数量选择观影人提交订单import random import time from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def snap_ticket(driver, target_url): # 打开详情页 driver.get(target_url) # 第一步循环监听购买按钮状态 while True: try: buy_btn WebDriverWait(driver, 1).until( EC.element_to_be_clickable(( By.XPATH, //div[contains(class,buy-link)]//span[contains(text(),立即购买)] )) ) buy_btn.click() break except Exception: # 按钮还没出现或不可点击刷新页面重新监听 driver.refresh() time.sleep(random.uniform(0.3, 0.8)) # 第二步等待票档加载默认选择第一个票档 time.sleep(0.5) ticket_btn WebDriverWait(driver, 3).until( EC.element_to_be_clickable(( By.XPATH, //div[contains(class,perform__order__select)]//li[1] )) ) ticket_btn.click() # 第三步点击提交订单 time.sleep(0.3) submit_btn WebDriverWait(driver, 3).until( EC.element_to_be_clickable(( By.XPATH, //div[contains(class,submit-wrapper)]//button )) ) submit_btn.click()看到这里你应该注意到了代码里用到的是 XPath 定位。这个写法比较稳定但不同时期、不同设备的页面结构会不一样所以这段代码里的定位表达式仅供参考实际使用时你需要用浏览器开发者工具重新定位。方法很简单打开演出详情页按 F12 进入开发者工具用左上角的箭头图标点击页面按钮然后右键选中高亮的 HTML 代码依次选择 Copy → Copy XPath 就行。不过有一点要注意直接拷贝出来的绝对 XPath 又长又脆弱页面稍微改动就会失效。我更建议你把包含“立即购买”这类特征文字的标签作为定位点用contains(text(),立即购买)这种方式去匹配容错率会高很多。3.3 关键参数选择逻辑写抢票脚本参数选择比功能实现更需要用心。我把几个实战中用到的关键参数和它的选择逻辑列出来参数推荐值选择逻辑刷新轮询间隔0.3~0.8秒随机固定高频刷新容易触发风控随机间隔更接近真人行为元素等待超时1~3秒热门场次开票瞬间页面变化快等待太长会错过点击窗口页面加载超时10秒开票瞬间服务器压力大加载慢是常态太短会误判失败重试次数不设上限靠异常捕获跳出抢票是循环监听没有“失败几次就放弃”的说法这里重点解释一下刷新间隔的选择逻辑。有人为了追求速度把刷新间隔设成 0.1 秒其实效果反而不好。一方面是请求太密集了容易触发风控另一方面是一个实际问题每次driver.refresh()都会重新加载整个页面如果页面还没加载完就又刷新就会陷入“永远加载不完”的死循环。所以我把间隔控制在 0.3 秒以上并且加上随机量既保证了反应速度又给页面加载留了时间。另一个细节是时间同步问题。我在第 1.1 节里说过别依赖本地时间去点按钮。在实际脚本里这个原则体现在“轮询页面状态”上——好不好抢以页面上按钮的可点击状态为准而不是以你电脑的时钟为准。这也是为什么整个主流程用的是WebDriverWait循环去等按钮而不是time.sleep()计算到点。4. 实战场上的常见坑与排查技巧这部分是我最想分享的内容。网上很多教程只教你怎么写代码不告诉你运行时会遇到什么幺蛾子。我把实战中踩过的坑按类型整理出来方便你直接对照排查。4.1 常见问题速查表问题现象可能原因排查思路session not created报错ChromeDriver 版本和 Chrome 版本不匹配对比chrome://version和 Driver 版本号NoSuchElementException元素找不到页面结构变化、定位表达式失效、元素在 iframe 里先打印页面源码确认元素是否存在浏览器顶部有“正在受自动测试软件控制”提示自动化特征未隐藏加入excludeSwitches参数点击按钮没反应按钮处于 disabled 状态不可点击用element_to_be_clickable等待真正可点击弹出滑块验证码触发风控人工处理不要写绕过逻辑页面跳回登录页cookies 过期重新执行登录保存 cookies4.2 环境类问题驱动版本不匹配是最常见的坑驱动版本不匹配是新手最容易踩的坑没有之一。症状是脚本一启动就报session not created很多人第一反应是代码写错了其实问题在驱动和浏览器的版本对不上。我的建议是升级驱动版本前先确认浏览器版本Chrome 是 126 就用 126 系的 Driver。如果你用的浏览器是 Edge原理一样EdgeDriver 的版本也必须跟 Edge 浏览器的版本对应。这个对应关系是硬性的不存在“差不多能用”的说法。4.3 页面元素定位失败怎么办元素定位失败是第二个高频问题。常见原因有三个页面结构改版、元素加载慢、元素在嵌入式页面里。定位失败的排查方法很简单分两步走。第一步打印页面源码看元素是否存在print(driver.page_source)搜索一下关键词比如“立即购买”如果源码里都没有说明元素还没加载或者页面结构变了。第二步截图看当前页面长什么样driver.save_screenshot(debug.png)这两个操作用不了几秒钟却能帮你节省大量试错时间。我自己的习惯是脚本每走到一个关键环节就把当前页面截个图保存下来万一后面出问题了回看截图就能知道是哪一步卡住了。4.4 关于验证码我的态度是人工处理抢票过程中尤其是在热门场次开票的时候很容易触发平台的验证码机制最常见的是滑块验证和短信验证。网上确实有人专门写代码去模拟滑块拖拽轨迹甚至用第三方识别平台去自动打码但我的建议很明确不要这么做。原因有两个。从安全角度说自动化绕过验证码是明显的对抗行为一旦被识别轻则本次购票失败重则账号被限制得不偿失从技术学习角度说写模拟滑块的代码对提升 Selenium 的技能帮助并不大它的核心只是计算像素偏移和模拟拖动轨迹属于脱离业务价值的轮子重复造。我在实战中的处理方式是脚本运行到验证码环节时通过声音和截图提醒我我手动处理掉验证码然后让脚本继续执行后面的流程。这样既绕过了只能人工完成的环节又不会把自己账号置于风控风险里。5. 使用边界与个人建议写到这里脚本的技术实现基本就完整了。但我还是想单独用一章来聊聊边界问题因为这是很多人在接触自动化脚本时容易忽略的部分。5.1 脚本的边界和法律意识一个成熟的抢票脚本技术上解决的只是“操作效率”问题它不改变你的购票资格也不创造票源。所以使用的时候有几个边界需要明确只用于个人购票场景不要用于抢票后加价转卖这是非常明确的违规行为不要批量注册账号、不要用脚本同时操作大量账号去抢占票额不要尝试绕过平台的验证码、风控和限购规则遵守目标平台的服务条款脚本的使用风险需要自己评估和承担从我自己的经验看把脚本限制在“个人提高操作效率”的范围内既是安全的红线也是技术上最舒服的状态。因为一旦你想去做对抗性的事就会陷入持续跟进平台风控变化的无底洞脚本的维护成本会变得极高早就超出了“业余工具”的范畴。5.2 这个脚本还能怎么扩展如果基础版脚本你已经跑通了跟着这个项目还能延伸出不少值得玩的技术方向用 Playwright 重写一版。Playwright 和 Selenium 的语法差异不小但核心思路是相似的重写一遍能让你更深刻地理解浏览器自动化的通用抽象。把日志写进文件。正式抢票时终端输出的日志一闪而过不如把每次刷新、每次点击、每次异常都记录到日志文件里方便复盘整个过程。加一个通知机制。脚本抢票成功或者遇到异常时通过邮件或者即时通讯工具给手机发一条提醒这样人不用一直盯在电脑前。这几个方向里我最推荐的是“加日志”因为抢票过程中的时间点、页面状态、点击耗时这些数据积累下来能帮你更清楚地分析脚本哪里可以优化。最后说个自己的体会吧。比起“抢到票”这个结果我更享受的是把一个不确定的流程变成一个确定性程序的过程。抢票脚本写完之后你会对“自动化”这件事产生一种新的感觉那些看起来拼手速、拼运气的场景其实背后都有一套可以被拆解、被优化、被程序化的逻辑。如果你也打算拿这个脚本练手我的建议是第一轮先别追求速度和成功率先把每个步骤手动走通把元素定位写稳定第二轮再来优化刷新节奏和异常处理。别一开始就想着全自动运行自动化这个东西先稳定再快。