ARTICLE DETAIL

资讯详情

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

12306自动查票抢票技术解析

12306自动查票抢票技术解析 一篇把「浏览器自动化抢票」讲透的实战文章从反检测、JS 高速余票检测、多车次优先级抢购到分车型座位适配全流程代码 思路拆解。目录本文仅做编程技术学习、浏览器自动化练习使用。⚠️重要声明本文所有内容仅用于技术交流与学习禁止将脚本用于恶意刷票、囤票、扰乱铁路购票秩序。使用第三方脚本抢票违反 12306 用户协议可能造成账号封禁、IP 限制请大家文明购票、遵守平台规则与相关法律法规。系统架构图下图展示配置层、控制层、浏览器层、12306 服务层之间的协作关系实线为正向调用虚线为反向作用flowchart TB subgraph 配置层 CONF[配置文件br/出发地 / 目的地 / 日期 / 车次优先级] end subgraph 控制层[Python 主程序] INIT[初始化 与 反检测] LOGIN[扫码登录] FILL[信息填充] LOOP[轮询抢票循环] ORDER[下单 与 选座] end subgraph 浏览器层[Chrome ChromeDriver] CDP[CDP 协议] DOM[页面 DOM] JS[JS 执行引擎 V8] end subgraph 服务层[12306] WEB[购票网页] RISK[风控 / 反爬] end CONF -- INIT INIT -- LOGIN -- FILL -- LOOP LOOP --|有票| ORDER ORDER --|提交订单| WEB INIT -.改写 webdriver.- CDP LOOP -.execute_script.- JS JS -.读写.- DOM DOM -.渲染.- WEB WEB -.风控检测.- RISK RISK -.封禁 / IP 限制.- 控制层架构要点解读小结把「找元素」这件事从 Python 侧交给浏览器内的 JS 引擎是本项目速度的关键转折点。前言一、项目整体介绍二、主程序核心思路与关键代码解析三、风险提示与使用规范必看四、拓展学习方向纯技术提升五、写在最后总结前言每到节假日、春运火车票总是一票难求。手速再快也拼不过秒空的车次于是很多技术爱好者会思考能不能用 Python 写一个脚本自动盯着余票、有票就抢答案是肯定的。本文基于Selenium 浏览器自动化技术完整讲解一套抢票脚本的设计思路与整体架构核心流程与关键技术点可直接阅读的核心代码片段一、项目整体介绍1. 实现功能本项目采用 Selenium 驱动 Chrome 浏览器模拟人工操作 12306 网页主要实现能力如下序号功能模块说明1反检测绕过自动隐藏 WebDriver 特征规避基础反爬识别2扫码登录唤起扫码登录规避复杂验证码识别难题3信息填充自动填入出发地、目的地、出行日期4高速查票高频轮询余票毫秒级识别可预订车次5多车次抢购首选车次无票自动切换备选车次优先级策略6座位适配区分高铁 / 普速列车自动选择对应座位类型7自动下单自动选择乘车人、提交订单下单后提醒用户手动支付2. 技术栈技术 / 库作用Selenium浏览器自动化核心库模拟鼠标、键盘、页面点击ChromeDriverChrome 浏览器驱动配合 Selenium 使用time/randomPython 标准库实现延时与随机间隔降低风控概率前端 JS 注入利用 JavaScript 直接操作 DOM大幅提升抢票速度为了方便维护和修改参数项目采用配置文件 主逻辑文件分离的结构不把所有参数硬编码在业务代码中做到「改参数不动逻辑」。3. 整体流程一览启动浏览器 → 隐藏 webdriver 特征 → 打开 12306 登录页 ↓ 唤起扫码登录人工扫码 ↓ 自动填充 出发地 / 目的地 / 日期 ↓ ┌─→ 点击查询 → JS 高速检测余票 ─┐ │ ↓ │ │ 无票 → 随机延时 → 继续 ─────┘ │ ↓ │ 有票 → 匹配优先级车次 │ ↓ │ JS 点击预订 → 选乘车人 → 选座位 │ ↓ └─ 提交订单 → 提示用户 10 分钟内支付4. 技术原理与系统架构理解本项目之前先搞清楚三个核心技术机制它们决定了「为什么这样写」而不是「那样写」。技术原理一Selenium 与浏览器的通信链路Selenium 并不直接控制浏览器而是通过W3C WebDriver 协议与 ChromeDriver 通信ChromeDriver 再通过CDPChrome DevTools Protocol控制浏览器Python 脚本 ──HTTP─▶ ChromeDriver ──CDP─▶ Chrome ──▶ 页面 DOM每一条find_element/click都要走完整链路跨进程通信开销大这是 Selenium 逐元素遍历缓慢的根因也是本项目用 JS 注入提速的出发点。技术原理二CDP 反检测注入Page.addScriptToEvaluateOnNewDocument与普通execute_script的本质区别注入方式执行时机反检测效果execute_script页面加载后执行时序晚易被首屏脚本探测addScriptToEvaluateOnNewDocument每个新文档加载前执行在任何业务脚本前改写navigator.webdriver更隐蔽本项目选择后者保证 12306 首屏风控脚本读取到的navigator.webdriver已经是undefined。技术原理三JS 注入为何能提速数十倍driver.execute_script只需一次跨进程调用把整段 JS 交给浏览器 V8 引擎本地执行所有 DOM 遍历、筛选、取值在浏览器内完成省去数百次 Selenium ↔ ChromeDriver ↔ 浏览器的网络往返一次返回结构化数据Python 侧直接拿到结果速度可提升数十倍。配置层与控制层分离参数改动不动逻辑便于跨场景复用控制层只发指令、不碰 DOM所有页面操作下放到浏览器层由 JS 引擎本地执行服务层是被动方12306 只能通过风控反制无法主动识别合法/非法客户端风险回路风控 → 封禁 → 控制层所以延时、随机化是必备手段而非可选项。二、主程序核心思路与关键代码解析核心优化高速余票检测函数传统 Selenium 循环遍历元素速度很慢这也是很多抢票脚本卡顿的主要原因。本项目采用JS 注入方式直接操作页面 DOM跳过元素定位耗时实现毫秒级识别可预订车次。关键代码片段def check_available_tickets(driver): 高速余票检测通过 JS 直接读取 DOM跳过 Selenium 元素定位耗时 tickets_info driver.execute_script( const tickets []; // 仅筛选当前可见的车次行隐藏行表示无此车型 const rows document.querySelectorAll( #queryLeftTable tr:not([style*display: none]) ); for (const row of rows) { const trainNumber row.querySelector(.number)?.textContent; const bookingBtn row.querySelector(.btn72); const ywStatus row.querySelector(td:nth-child(8))?.textContent; // 同时判断有预订按钮 有车次号 有余票状态 if (bookingBtn trainNumber ywStatus) { tickets.push({ trainNumber: trainNumber, hasButton: true, status: ywStatus }); } } return tickets; ) return tickets_info 技术亮点1 选择器精准过滤直接通过 CSS 选择器筛选可见车次行排除隐藏的无用车次2 多重条件判断同时判断「是否有预订按钮」「是否为候补票」过滤无效车次避免误抢候补3 JS 性能优势JS 在浏览器内直接执行效率远高于 Selenium 逐层元素查找是提升抢票速度的核心优化。绕过 12306 自动化检测12306 会检测浏览器的webdriver标识以此判断当前是否为自动化脚本。一旦被识别登录环节的滑动验证码就会变得频繁且复杂。我们通过 Chrome 调试协议CDP在页面加载前篡改该属性实现基础绕过关键代码片段# 注入代码隐藏 webdriver 特征绕过网站自动化检测 driver.execute_cdp_cmd( Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, {get: () undefined}) } )该代码必须放在浏览器打开网页之前执行确保每个新加载页面的navigator.webdriver都被改写为undefined从而有效规避账号密码登录时的滑动验证码拦截。核心思路优先使用 JS 点击配合合理等待避免元素遮挡、加载失败等问题。自动填充出发地、目的地、日期模拟人工在输入框填写站点与日期结合Keys.ENTER确认下拉联想选项完全贴合人工操作逻辑# 示例自动填充出发地 driver.find_element(By.XPATH, //*[idfromStationText]).click() driver.find_element(By.XPATH, //*[idfromStationText]).clear() driver.find_element(By.XPATH, //*[idfromStationText]).send_keys(conf.from_station) time.sleep(1) # 等待下拉联想列表加载 driver.find_element(By.XPATH, //*[idfromStationText]).send_keys(Keys.ENTER)目的地、日期填充逻辑与上方一致格式统一、便于维护。关键点必须等待联想列表加载完成后再回车否则会因元素未就绪而填入空值。核心轮询持续查票 多车次抢购逻辑这是整个脚本最核心的业务逻辑采用死循环不断查询余票一旦检测到可预订车票立即按配置的车次优先级执行抢购。核心逻辑梳理1. 循环判断查询按钮状态按钮可点击则自动刷新车次列表 ↓ 2. 调用高速余票检测函数判断当前是否有可预订车票 ↓ 3. 无票 → 随机短延时 → 继续下一轮查询随机延时降低风控概率 ↓ 4. 有票 → 遍历优先级车次列表逐个匹配目标车次 ↓ 5. 匹配成功 → JS 点击预订按钮 → 关闭弹窗 → 选择乘车人 ↓ 6. 区分 高铁 / 普速列车自动选择对应座位类型 ↓ 7. 提交订单 → 引导用户 10 分钟内手动完成支付关键代码片段轮询主体# 定位查询按钮 query_tag driver.find_element(By.XPATH, //*[idquery_ticket]) while True: # 1. 按钮可用则刷新车票class 为 btn92s 表示可点击状态 if query_tag.get_attribute(class) btn92s: driver.execute_script(arguments[0].click();, query_tag) # 2. 获取当前可预订车次 available_tickets check_available_tickets(driver) if not available_tickets: print(暂无可预订车票继续监控...) time.sleep(random.uniform(0.097, 0.345)) # 随机延时降低风控概率 continue # 3. 按优先级尝试抢购多个车次 for train_number in conf.train_numbers: # 匹配目标车次排除候补票 target_ticket next( ( t for t in available_tickets if t[trainNumber] train_number and 候补 not in t[status] ), None ) if target_ticket: # 执行预订、选乘车人、选座位、提交订单逻辑 print(f成功锁定车次{train_number}请尽快支付) return设计要点解读随机延时random.uniform(0.097, 0.345)避免固定间隔被风控识别为机器行为生成器 next在可预订车次列表中按优先级快速匹配命中即返回避免全量遍历候补过滤通过候补 not in t[status]排除候补票只抢真实可预订车票。分车型座位选择适配针对高铁G/D、普速列车Z/K两种车型做差异化座位选择车型座位选择策略实现方式高铁 / 动车默认选择靠窗 F 座通过 JS 直接点击选座元素普速列车下拉框选择硬座 / 硬卧 / 软卧通过 JS 修改下拉框选中状态并触发事件该部分大量使用 JS 操作页面元素解决普通点击不稳定、下拉框选择失效等问题。原因Selenium 原生Select类对 12306 自定义下拉框支持不佳需通过 JS 触发change事件才能让页面正确响应。三、风险提示与使用规范必看 请在使用前务必完整阅读以下条款违规使用风险自负。合规第一本代码仅用于Selenium 自动化、前端 JS 交互、爬虫技术学习严禁用于商业、恶意抢票、批量囤票账号安全建议使用小号测试高频刷新、频繁提交订单有账号封禁风险IP 限制不要将延时设置过小高频请求会导致 IP 被临时限制访问 12306功能边界本脚本仅实现自动下单支付环节保留人工操作不涉及任何破解、绕过支付流程的逻辑页面变动12306 会不定期更新页面结构、元素 ID、XPath代码可能随页面改版失效需自行微调元素定位规则。四、拓展学习方向纯技术提升如果想继续深入学习浏览器自动化、爬虫相关技术可以基于本项目拓展以下方向消息推送增加邮件 / 微信消息推送抢到票后主动提醒用户异步接口版学习aiohttp结合 12306 公开接口实现纯接口版余票监控速度更快验证码识别研究图片验证码、滑块验证码识别技术纯图像识别学习日志记录增加日志功能记录每一轮查询状态与时间便于复盘优化代理 IP学习代理 IP 使用理解风控与反风控的技术原理。五、写在最后12306 抢票脚本本质就是浏览器自动化模拟人工操作核心难点在于页面元素适配XPath / 选择器随改版失效反检测隐藏自动化特征执行速度优化JS 注入替代 Selenium 元素查找希望本文能帮助大家理解 Selenium 实战、JS 注入、自动化脚本的设计思路。再次呼吁技术要用到正道上出行购票优先使用官方 App、小程序共同维护公平的购票环境。如果文章对你有帮助欢迎点赞、收藏、评论交流技术问题
返回列表