十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

用Python+Selenium写12306抢票脚本:登录、查票、下单全流程

用Python+Selenium写12306抢票脚本:登录、查票、下单全流程 1. 抢票需求与自动化破局思路1.1 为什么我会想到用Selenium做抢票脚本每年春节前一个月我的手机里就会堆满亲戚朋友发来的“加速抢票”链接。说实话那些助力的作用微乎其微真正能解决问题的还是12306官方渠道。但手动刷新、盯着余票信息的日子我相信每个经历过的人都懂——尤其是热门线路放票那一刻网卡一下整张票就没了。我在一家互联网公司做后端开发平时主要跟Java和Go打交道Python用得不算多但每年到了这个时候我都会写个小脚本帮自己和家里人抢票。为什么不直接在12306 App里抢原因很简单网页端的自动化操作空间比App大得多而且Selenium能模拟人类操作在需要登录、查票、提交订单的场景下比直接调接口稳定得多。Selenium是一个浏览器自动化测试框架它的核心能力就是驱动一个真实的浏览器Chrome、Firefox等去执行你在浏览器里能做的所有操作打开网页、输入账号密码、点击按钮、切换页面。你可能会问为什么不直接用爬虫模拟HTTP请求去调12306的接口我试过最大的问题是12306的接口签名和风控机制极其复杂尤其在春运这种特殊时期模拟请求很容易被识别并拦截。而Selenium驱动的是真实浏览器有完整的浏览器指纹、Cookie、渲染环境被识别为机器人的概率低得多。这篇文章我会完整拆解我是怎么用PythonSelenium写出一套春节抢票脚本的包括登录、查询余票、提交订单、处理验证码、应对候补购票的全流程以及踩过的坑和最终的解决方案。1.2 抢票脚本的整体目标与功能拆解在动手写代码之前我习惯先把需求拆干净。这套抢票脚本我给自己定的目标是自动登录能读取本地保存的Cookie实现免登录操作如果Cookie失效则弹出登录窗口人工扫码。自动查询余票定时刷新指定日期、指定车次的余票信息一旦发现目标车次有余票就立即触发下一步。自动提交订单找到有余票的车次后自动选择乘车人、席别提交订单并在下单页面停留等待确认。异常处理遇到验证码、网络超时、按钮加载延迟等情况时脚本不崩溃、不死循环而是按预设策略处理。这个目标清单看起来很简单但真正实现的时候每一个环节都有隐藏的坑。比如12306的登录页面经常改版Chrome的WebDriver版本必须和浏览器版本严格匹配页面元素的定位方式会因为页面异步加载而失效……这些细节我都会在后文逐一展开。需要说明的是这套脚本解决的是“自动化和效率”问题它并不能保证100%抢到票更不是用来做黄牛生意的。我的经验是脚本最大的价值在于把“盯盘”这种机械劳动从人身上剥离出来让你在放票后的第一时间自动完成整套下单动作省去手动刷新、手动填单的时间差。这也正是Selenium这种自动化工具的核心价值所在。2. 环境准备与基础工具选型2.1 Python版本的考量与安装细节如果你已经有Python环境这一步可以跳过。但如果你是从零开始我想多说几句版本选择的问题。我推荐使用Python 3.9到3.12之间的版本。为什么不是最新的3.13因为Selenium库本身对Python版本的适配非常成熟但有些第三方依赖比如用于处理验证码的深度学习库在过新的Python版本上可能会出现预编译轮子缺失的问题源码编译又会浪费大量时间。3.10或3.11是我实测最稳妥的选择一方面Selenium的API完全兼容另一方面后续如果要用ddddocr这类验证码识别库安装时也不会遇到兼容性报错。安装Python时有一个细节必须注意在Windows安装向导的第一步一定要勾选“Add Python to PATH”复选框。这一步漏掉的话你会在命令行中输入python时得到一个“不是内部或外部命令”的错误然后被迫手动配置环境变量纯属浪费时间。装好之后在命令行中验证一下版本python --version正常会输出类似Python 3.11.5的版本信息。我看到有些朋友在安装后输入python命令没有反应或者输出的不是期望的版本号这通常是因为系统里残留了旧版本Python或者从Microsoft Store安装的Python与预期冲突。解决思路很简单打开“设置-应用-应用和功能”把不需要的Python版本全部卸载干净再重新安装一次。2.2 Selenium库与浏览器驱动的版本匹配安装Selenium库本身非常简单pip install selenium但真正让我第一次翻车的是Chrome浏览器与ChromeDriver的版本匹配问题。Selenium通过ChromeDriver与浏览器通信如果两者版本不一致Selenium会直接抛出SessionNotCreatedException异常连浏览器窗口都打不开。这里我推荐一个极其顺手的方法用WebDriver Manager自动处理版本对应关系不需要手动下载Driver。安装命令pip install webdriver-manager然后用它来启动浏览器from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice)WebDriver Manager会在第一次运行的时候自动去匹配本地已安装Chrome的版本号下载对应的Driver到本地缓存。这比我当年手动去ChromeDriver官网查版本、下载、解压、配置PATH的那套流程省事太多了。提示如果你使用的是Firefox对应需要安装Selenium的geckodriver但就我个人的体会抢票场景下Chrome的兼容性和性能表现更稳定推荐优先选用。2.3 IDE选择VSCode还是PyCharm关于IDE我的看法是用什么不重要能打断点和看变量值最重要。我个人偏好VSCode原因有两点一是轻量启动速度快二是对Selenium脚本的调试支持非常完善。你只需要安装Python官方插件然后在代码行号左侧点击红色圆点设置断点按F5启动调试模式就能实时看到driver执行到哪一步、页面上是什么状态。如果你有PyCharm专业版调试体验也不错尤其是DataSpell和PyCharm在显示复杂对象结构时更直观。但PyCharm社区版其实已经足够用了Selenium脚本本质上就是普通Python程序不需要专业版额外的框架支持。这里我还想分享一个务实的建议抢票脚本通常要长时间运行千万不要用IDE直接跑完整脚本然后挂一晚上。因为IDE在长时间空闲后可能会自动断开会话或者系统休眠导致USB设备挂起WebDriver是通过Chrome DevTools Protocol通信的休眠后整个浏览器进程都冻结了。正确的做法是在VSCode或PyCharm里调试好逻辑确认无误后用命令行方式后台运行python ticket_grabber.py配合nohupLinux/macOS或者让它在前台运行但关闭系统自动休眠。3. 核心实现登录、查票、下单全流程3.1 登录态处理Cookie持久化的正确姿势12306的登录页面有两种认证方式账号密码登录和扫码登录。账号密码登录在自动化场景下麻烦重重——不仅需要识别打乱的验证码图片而且频繁登录还会触发账号风控。我强烈建议优先使用扫码登录然后保存Cookie复用登录态。具体做法是首次运行时打开登录页面人工用12306 App扫码登录登录成功后把浏览器的Cookie序列化保存到本地JSON文件。之后的运行直接加载这个文件注入到浏览器的Cookie存储中模拟已登录状态。核心代码如下import json import pickle from selenium import webdriver def save_cookies(driver, pathcookies.json): with open(path, w) as f: json.dump(driver.get_cookies(), f) def load_cookies(driver, pathcookies.json): with open(path, r) as f: cookies json.load(f) for cookie in cookies: driver.add_cookie(cookie)有一个细节必须提醒加载Cookie之前必须先访问一次域名下的任意页面比如先打开https://www.12306.cn的首页让浏览器建立这个域名下的会话基础然后再执行add_cookie否则Cookie不会生效。这是因为Selenium要求添加Cookie时必须已经处于该Cookie所属的域下。Cookie的有效期通常是几天到几周不等。如果加载Cookie后发现页面自动跳转回了登录页说明Cookie已经过期脚本里需要设置一个检测逻辑如果当前URL包含login关键字就触发重新扫码流程。3.2 余票查询页面元素的定位策略12306的余票查询页面核心元素是车次列表表格。Selenium定位元素常用的有find_element(By.ID, ...)、find_element(By.CLASS_NAME, ...)、find_element(By.XPATH, ...)等。但在12306这个页面上我遇到的最大问题不是定位不到而是页面元素异步加载导致的时序问题。你查询余票后车次信息并不是立刻渲染出来的而是由前端Ajax请求返回后动态拼接的表格。如果脚本刚点击查询就立刻去寻找车次行必然会抛出ElementNotVisibleException。解决方案是使用WebDriverWait显式等待from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By wait WebDriverWait(driver, 10) rows wait.until( EC.presence_of_all_elements_located((By.XPATH, //tbody[idqueryLeftTable]/tr)) )这里我用了XPATH定位到queryLeftTable这个表格中的所有行。12306的车次列表结构有一个特殊之处它会渲染一些不可见的占位行用于分隔不同车次这些行只有部分字段如果直接遍历会报错或者拿到空数据。需要额外判断一行中是否存在车次编号元素。解析重点车次是否还有余票的逻辑我把它封装成了一个函数def parse_ticket_info(driver, target_train_no): rows driver.find_elements(By.XPATH, //tbody[idqueryLeftTable]/tr) for row in rows: try: train_no row.find_element(By.XPATH, .//div[contains(class,train-no)]).text.strip() except: continue # 这是占位行跳过 if train_no target_train_no: # 检查按钮状态需要判断是“预订”还是“无票” booking_btn row.find_element(By.XPATH, .//a[contains(class,btn72)]) if booking_btn.text.strip() 预订: return True, booking_btn return False, None对于目标车次我不关心它是一等座还是二等座是否有票只要页面上出现“预订”按钮就代表有可用席位立即触发下单流程。3.3 下单提交乘车人选择与席别优先级点击“预订”按钮后页面会跳到订单确认页面。这里有两步关键操作第一步选择乘车人。12306的订单页面中乘车人列表是一个一个div卡片组成的每个卡片上有姓名和证件号。我采取的策略是遍历所有乘车人卡片比对名字勾选目标乘车人前面的复选框passenger_list driver.find_elements(By.XPATH, //ul[idpassenger]/li) for p in passenger_list: name p.find_element(By.XPATH, .//label).text.strip() if name in target_passengers: checkbox p.find_element(By.XPATH, .//input[typecheckbox]) if not checkbox.is_selected(): checkbox.click()第二步选择席别。这里值得注意的是席别优先级。春运期间二等座往往比一等座更难抢商务座虽然贵但余票偶尔还有。我的做法是按优先级列表依次检查如果一等座没票就选二等座seat_priority [二等座, 一等座, 商务座] for seat in seat_priority: try: seat_radio driver.find_element(By.XPATH, f//label[contains(text(), {seat})]/preceding-sibling::input) if seat_radio.is_enabled(): seat_radio.click() break except: continue点击提交订单之前从页面读取一下显示的票种、席别、票价、乘车人姓名跟预设的目标做一致性校验有偏差就终止流程并截图留存。这一步是我踩过坑之后的教训——有一次脚本因为页面默认选择了一个不需要的高铁票直接提交了订单结果差点默认支付还好我在下单页面设置了人工确认的WebDriverWait等待。3.4 验证码处理滑块与图片识别的实战经验12306的登录和提交订单环节都可能出现验证码。常见的验证码有两种图片点选和滑块验证。图片点选验证码让用户点击指定的文字12306已经在前几年取消了最常见的这类型验证码但在某些异常风控场景下还会出现。处理思路有两种一种是接入打码平台如超级鹰把验证码图片截图之后发送到平台由平台返回坐标脚本点击对应位置另一种是本地用ddddocr等OCR库来识别文字再根据文字坐标定位。就准确率而言打码平台对12306这类复杂验证码的识别率明显高于本地OCR但速度和费用都需要考虑。滑块验证码12306的滑块验证比较初级是那种拖动滑块补全拼图的样式。Selenium处理滑块的核心思路是模拟人类拖拽的轨迹。最忌讳的是用ActionChains的drag_and_drop一把拖过去这种匀速运动轨迹很容易被识别为机器操作。正确做法是分段拖动模拟先快后慢的物理规律from selenium.webdriver import ActionChains def smart_drag_slider(slider_element, target_x): actions ActionChains(driver) actions.click_and_hold(slider_element) current 0 while current target_x: # 模拟加速、减速过程 step 10 if current target_x * 0.7 else 5 actions.move_by_offset(step, random.randint(-2, 2)) current step actions.release() actions.perform()注意要import random每一步的纵向偏移也随机化这样轨迹看起来才像人拖的。但我必须说句实话滑块验证码的效率天花板很低。即使模拟轨迹很逼真也不能每次都成功。所以我的脚本里对验证码的处理策略是如果三次尝试都没通过就干脆停止自动化弹窗提示人工介入。3.5 候补购票为什么脚本最终要回归官方候补聊到这儿我觉得有必要说说一个很现实的技术演进12306的候补购票功能在春运期间的购买优先级其实比任何抢票脚本都高。候补购票是12306官方推出的机制当某车次余票售罄时你可以提交候补订单并支付预付款如果系统释放退票、改签产生的余票会按候补顺序依次分配。官方系统的优先级、实时性和稳定性是外部脚本无法企及的。更关键的是12306明确禁止第三方软件抢票脚本抢票行为本身就处于灰色地带。我的脚本虽然写了自动抢票功能但在实际使用中我越来越倾向于把它定位成一个“监控提醒助手”而不是“抢票机器”脚本持续监控车次余票状态一旦发现放票就立刻通过Server酱推送通知到手机我去手动打开12306 App或者网页下单。如果候补通道开放脚本会引导我先去官方候补排队然后再用脚本作为补充。诚然2024年以来12306在风控层面做了很多升级包括动态表单校验、浏览器指纹采集、行为轨迹数据分析等Selenium脚本的生存空间在不断压缩。我的经验是自动化工具的价值在于“快人一步发现问题”而最终解决问题大概率还是要靠官方机制人的及时响应。这部分经验我在第5节和第6节还会进一步展开。4. 反检测与稳定性优化4.1 隐藏Selenium自动化标识的几种方案当Selenium启动Chrome时浏览器会带上一个navigator.webdriver属性值为true。网页端可以通过检查这个属性来识别自动化环境。12306的风控系统肯定会检查这一点。最常用的隐藏方法是修改Chrome启动参数启用excludeSwitchesfrom selenium.webdriver.chrome.options import Options options Options() options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_experimental_option(useAutomationExtension, False) options.add_argument(--disable-blink-featuresAutomationControlled)这三个参数组合起来可以隐藏大部分基础检测痕迹移除顶部的“Chrome正受到自动测试软件的控制”提示条、关闭自动化扩展、禁用Blink渲染引擎下的自动化标记。但只有这些还不够。navigator.webdriver属性依然可能被读取到。为了彻底擦除这个标记可以在页面加载前注入JS代码覆盖该属性driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }); })注意execute_cdp_cmd是Chrome DevTools Protocol的命令接口需要ChromeDriver支持实测对Chrome有效。4.2 浏览器指纹与请求行为伪装即便webdriver标记被擦除风控系统还能通过浏览器指纹来识别异常。例如Canvas指纹、WebGL渲染器信息、屏幕分辨率、时区、User-Agent、插件列表等。普通自动化浏览器缺少一些真实浏览器常见的插件或者渲染细节都存在被识别的可能性。在12306抢票这个场景里我的经验是不需要过度完美但也别太破绽百出。具体操作上有几个点值得做设置合理的窗口大小真实用户通常不会用默认800x600的窗口操作把窗口调整到常见分辨率比如1920x1080。关闭无头模式Headless无头模式省资源但无头浏览器的指纹与现实浏览器差异明显很容易被识破。抢票脚本建议开启有头模式挂在后台跑就好。随机化操作间隔脚本里的每个动作之间加入随机的延迟时间模拟人阅读屏幕的时间。不要每个操作都间隔固定的0.5秒那样会被时序分析识别出机器特征。与此同时我还需要提醒一个很多人忽略的点运行机器人的那块屏幕和网络环境。如果IP频繁变化、或者通过公共流量池的出口访问12306都可能触发账号风控。最稳妥的方式是在固定网络环境比如家里宽带下运行脚本。4.3 超时重试与断线重连机制抢票高峰期12306的服务器压力巨大页面可能加载超时、按钮点击无响应、浏览器突然白屏这些都是常态。脚本必须有一套健壮的超时重试机制否则跑到一半挂掉等于白熬一夜。我常用的模式是装饰器加重试循环import time from selenium.common.exceptions import TimeoutException, WebDriverException def retry_on_exception(max_retries3, delay2): def decorator(func): def wrapper(*args, **kwargs): for i in range(max_retries): try: return func(*args, **kwargs) except (TimeoutException, WebDriverException) as e: if i max_retries - 1: raise time.sleep(delay * (i 1)) return None return wrapper return decorator另外我还建议每隔一段时间重启一次浏览器。长时间运行的浏览器进程内存占用逐步上升ChromeDriver的通信也会出现微妙的不稳定。我实测跑4到6个小时后重启一次浏览器会让整个流程稳定很多。在重启的时候重新加载Cookie然后直接跳到查询页面成本很低。4.4 Windows休眠与系统电源策略调整一个特别容易被忽略的问题电脑休眠导致脚本中断。很多朋友把脚本挂在自己的办公电脑或个人笔记本上然后人离开电脑默认30分钟无操作进入睡眠。系统一睡眠所有进程全部冻结时间一到脚本就失控了——等回到电脑前可能早就错过了最佳抢票窗口。解决方法是调整电源计划在Windows的“设置-系统-电源和睡眠”中把“接通电源时睡眠”改为“从不”。同时把“硬盘关闭”也设为0永不。如果你用的是笔记本还要留意合盖的默认行为改成“不进行操作”。如果你有云服务器可以考虑把脚本部署到Linux服务器上。抢票脚本对CPU、内存要求不高1核2G的入门云主机完全够用关键是7x24小时在线。部署方法我在第6节专门讲。5. 常见问题排查与经验速查5.1 典型报错场景与解决对照表为了让后来者少走弯路我把我实操里遇到的问题整理成了一个大对照表。这些报错信息几乎是每个Selenium新手都会遇见的报错信息发生场景解决方法SessionNotCreatedException启动浏览器时Chrome与ChromeDriver版本不匹配用webdriver-manager自动匹配NoSuchElementException查找页面元素时元素未加载完成改用WebDriverWait直到元素出现检查定位表达式ElementClickInterceptedException点击按钮时元素被其他弹窗或遮罩遮挡先关闭弹窗或滚动到元素可见位置再点击ElementNotInteractableException操作输入框时元素在页面上但不可交互检查是否处于隐藏状态需要用JS强制设置值TimeoutException等待加载时目标状态一直未出现检查网络或页面改版延长等待时间并重试InvalidCookieDomainException添加Cookie时未先访问目标域名页面就添加Cookie先driver.get(url)再注入5.2 12306页面改版对脚本的影响与应对12306前端页面的更新频率并不算低尤其是查询接口的返回结构偶有微调。我的脚本曾经因为一个CSS类名的变化整个查票模块直接失效。面对这类风险我有两条经验第一定位元素尽量用稳定的ID和结构化属性避免用一次性生成的class名称。12306的很多样式类名是带哈希后缀的比如btn72_xxx_1234567这种类名前后端联调时一压缩就会变化。优先使用id、name或固定的text来定位。第二脚本里加一个“页面结构自检”启动时先检查当前页面是否包含预期关键元素比如登录框、查询按钮如果没有立刻截图并终止而不是盲目往下执行报一堆错。这样即使页面改版你醒来看一眼截图就知道问题出在哪儿。5.3 抢票高峰期的高可用策略抢票时间是明确且固定的。每年12306提前15天放票放票当天的特定时间点比如8点、10点、12点、14点、16点等整点就是真正的冲刺时刻。我的策略是提前半小时启动脚本进入查询页面并保持会话然后在放票时间点前1分钟开始高频刷新。高频刷新的频率别太夸张我实测每3到5秒查询一次就可以。刷得太快反而容易被服务端限流甚至封IP得不偿失。刷新余票信息有两种方式一种是driver.refresh()整个页面刷新另一种是直接重新点击查询按钮。后者更轻量而且避免了页面重载带来的状态丢失。优先采用“点击查询按钮”的方式。5.4 多车次、多日期的轮询调度一个常见需求是我不仅抢某一趟车而是希望多天多车次广撒网。这在脚本里就是一个循环调度的问题。我用一个配置文件来管理目标列表结构大概是{ date_range: [2025-02-06, 2025-02-07, 2025-02-08], trains: [G1, G3, G5, G7], passengers: [张三, 李四], seat_priority: [二等座, 一等座, 商务座] }定时器模块遍历日期和车次因为12306只允许查询单日单程的车次信息所以脚本内部需要循环切换日期查询。注意每切换一次日期查询页面的加载时间在1到3秒不等轮询时要把这个延迟算进去不要用sleep(2)这种固定等待而是结合WebDriverWait和轮询逻辑。6. 部署到云服务器实现7×24小时值守6.1 Linux服务器部署Selenium的环境准备如果你决定把脚本部署到云服务器上环境准备要比本地多几个步骤。以Ubuntu 22.04为例核心步骤如下# 更新系统 sudo apt update sudo apt upgrade -y # 安装Python环境和pip sudo apt install -y python3-pip python3-venv # 安装Chrome浏览器 wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - sudo sh -c echo deb [archamd64] http://dl.google.com/linux/chrome/deb/ stable main /etc/apt/sources.list.d/google-chrome.list sudo apt update sudo apt install -y google-chrome-stable # 创建虚拟环境 mkdir ~/ticket cd ~/ticket python3 -m venv venv source venv/bin/activate # 安装依赖 pip install selenium webdriver-manager requests有两点提醒一是服务器上没有图形界面Chrome需要依赖一些系统库才能正常运行如libatk、libgtk等通常在安装Chrome时这些依赖会自动装好如果后面启动时报“error while loading shared libraries”用apt --fix-broken install修复依赖即可。二是中文显示问题如果不想自己折腾字体直接配置服务器 locale 为 UTF-8 并安装fonts-noto-cjk避免页面上中文乱码导致元素定位失败。6.2 用systemd管理脚本常驻进程nohup python ticket.py 这种方式虽然简单但一旦进程崩溃没有人会去自动拉起。放在服务器上我推荐用systemd来做守护。创建一个service文件sudo vim /etc/systemd/system/ticket.service内容如下[Unit] DescriptionSpring Festival Ticket Grabber Afternetwork.target [Service] Typesimple Userubuntu WorkingDirectory/home/ubuntu/ticket ExecStart/home/ubuntu/ticket/venv/bin/python /home/ubuntu/ticket/ticket.py Restartalways RestartSec10 EnvironmentDISPLAY:99 [Install] WantedBymulti-user.target注意EnvironmentDISPLAY:99这一行如果你需要在服务器上运行有头模式的Chrome必须配合Xvfb虚拟显示服务。安装命令是sudo apt install -y xvfb然后用Xvfb :99 -screen 0 1920x1080x24 启动虚拟屏幕。启动服务sudo systemctl daemon-reload sudo systemctl enable ticket sudo systemctl start ticket之后查看日志用journalctl -u ticket -f非常方便。这个方案比手动nohup要可靠得多进程挂掉10秒内自动重启我2024年春节就是用这套配置跑完整个春运周期的。6.3 日志、告警通知与数据留存在无人工值守的场景下告警通知是刚需。推荐用Server酱方糖推送消息到微信理由只有一个注册即用免费额度足够个人使用。在脚本的关键节点埋点推送脚本启动时推送一条“开始监控”通知。检测到目标车次有票时立刻推送车次、日期、席别信息。提交订单成功时推送订单信息要求尽快支付。脚本遇到致命异常时推送错误摘要。Server酱的调用非常简单import requests def send_serverchan(title, content): # 这里的SEND_KEY需要替换成你自己的 url fhttps://sctapi.ftqq.com/{SEND_KEY}.send requests.post(url, data{title: title, desp: content})日志方面不要只依赖systemd的journal脚本内部使用Python的logging模块同时输出到文件和控制台每个抢票周期的日志按日期分文件保存。这样即使某个周期没抢到票回来后还能复盘是哪个环节慢了两秒。7. 合规边界与理性期待7.1 第三方抢票工具的法律风险说了这么多实现细节我必须停下来认真说一段合规边界的问题。12306官方在2015年就发布过公告明确表示禁止任何第三方软件和非官方渠道进行抢票并会对频繁访问的行为进行限制和账号封禁处理。使用Selenium自动化抢票本质上是绕过或干扰网站正常操作流程的行为法律层面确实存在争议。另外需要特别警惕的是任何收取费用的抢票服务或外挂都涉嫌扰乱市场秩序这是明确的法律红线。我写这套脚本的初衷是给家人抢票定位是学习自动化技术和解决个人购票的应急需求绝不会把它包装成付费服务。如果你也想做类似的事情请务必守住这个边界。更重要的是自动下单成功后务必在10分钟内完成支付否则订单会被取消。脚本要设置一个明确的下单后停止机制不要让同一趟车重复提交订单否则会占用票额、影响其他乘客购票也有可能被系统判定为异常行为。7.2 为什么最终建议优先使用官方候补写到这里我想分享一个经历过多个春运周期之后的最大心得12306的候补购票在春运期间的价值超过任何脚本抢票。为什么这么说因为候补购票的优先级是内置在12306的系统里的。当有退票或改签产生的余票后系统会按照候补顺序自动分配这个分配流程不经过任何外部脚本。而市面上那些“刷票软件”看起来能抢到票本质上就是高频刷新自动下单速度快但风险高账号容易被封而且不一定能抢过系统本身的候补队列。所以我现在的推荐策略是三层组合第一层12306 App官方候补首选方案提交候补订单付款排队。第二层Selenium监控加提醒发现有余票时第一时间人工确认并快速下单。第三层每天固定时间去查看候补队列状态根据剩余时间调整候补车次和席别。这套组合拳的核心逻辑是官方机制解决确定性自动化解决时效性。如果你候补排在很前面大概率能在开车前几天收到兑现成功的通知脚本只是多了一道保险。7.3 技术学习价值与后续扩展方向抛开抢票这个具体场景用Selenium做浏览器自动化这件事本身是非常值得入门的技术投资。你会发现学会了Selenium之后很多重复性劳动都有了自动化的可能性比如定时填充表单、爬取需要登录的报表数据、做网页端的自动化回归测试、批量下载某个平台的文件等等。就这个抢票脚本本身如果你有兴趣继续扩展我建议从这几个方向入手GUI化用PySimpleGUI做一个简单的图形界面不用改代码就能调整日期、车次、乘客。多账号支持改造Cookie管理模块支持多账号轮询团队一起使用。多平台支持把查询逻辑抽离出来同样的思路应用到其他购票平台但务必注意合规风险。数据可视化把每日余票量、放票时间规律做数据统计用matplotlib画趋势图帮助你反向理解12306的票池投放规律。我个人在实际操作中最深的体会是抢票这件事比拼手速只是表象本质上是信息差和决策速度的比拼。脚本替代的是“盯盘”和“提交订单”这些机械动作但真正决定成败的是你对放票节奏的判断、对候补队列的管理、以及对备选方案的准备。把这套技术打磨好带给你最大的收获可能不是抢到的那张票而是面对问题时拆解、建模、自动化解决的能力——这比一张车票值钱得多。
返回列表