12306 自动抢票脚本全解析:从模块拆解到实战应用

12306 自动抢票脚本全解析:从模块拆解到实战应用

在日常出行中,12306 抢票往往是令人头疼的环节。本文将对一款基于 Selenium 实现的 12306 自动抢票脚本进行全方位拆解,从模块功能、代码逻辑到实战注意事项,帮助读者深入理解并灵活运用该脚本。

一、脚本整体架构与核心依赖

该脚本采用面向对象的编程思想,封装为TrainTicketBot类,核心依赖selenium库实现浏览器自动化操作,time库用于控制操作间隔。整体流程可概括为:初始化浏览器配置→等待用户扫码登录→自动填写车次信息→提交购票订单。

核心依赖安装

pip install selenium
# 注意:需匹配Chrome浏览器版本下载ChromeDriver,并配置系统环境变量

二、模块逐行拆解与功能解析

1. 导入模块段

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
  • time:提供时间休眠功能,避免操作过快触发 12306 反爬机制,同时等待页面元素加载。
  • webdriver:Selenium 核心模块,用于启动浏览器并执行自动化操作。
  • By:指定元素定位方式(如 XPATH、ID、CLASS_NAME 等),是 Selenium 定位页面元素的核心枚举类。
  • Options:Chrome 浏览器配置选项类,用于定制浏览器启动参数(如禁用自动化检测、最大化窗口等)。

2. 类初始化方法(init

def __init__(self, from_station, to_station, departure_time):
    self.from_st = from_station  # 出发站
    self.to_st = to_station      # 到达站
    self.de_time = departure_time  # 出发日期
    self.options = Options()
    # 禁用Chrome的自动化检测提示,规避12306反爬机制
    self.options.add_experimental_option('excludeSwitches', ['enable-automation'])
    self.options.add_argument('--disable-blink-features=AutomationControlled')
    self.options.add_argument('--disable-infobars')  # 禁用浏览器信息提示栏
    self.driver = webdriver.Chrome(self.options)     # 启动Chrome浏览器
    self.driver.maximize_window()  # 最大化浏览器窗口,避免元素定位偏差

核心功能

  • 接收外部传入的出发站、到达站、出发日期参数并赋值为实例属性;
  • 配置 Chrome 浏览器启动参数,核心是规避 12306 对自动化工具的检测;
  • 初始化浏览器实例并最大化窗口,确保页面元素完整展示。

3. 元素存在性校验方法(is_element_exist)

def is_element_exist(self, element):
    # 判断元素是否存在
    flag = True
    try:
        self.driver.find_element(By.XPATH, element)
        return flag
    except:
        flag = False
        return flag

核心功能

  • 封装通用的元素存在性校验逻辑,通过 XPATH 定位元素;
  • 利用 try-except 捕获元素未找到的异常,返回布尔值标识元素是否存在;
  • 解决页面加载异步性问题,避免因元素未加载完成导致脚本报错。

4. 核心抢票逻辑方法(check_ticket)

该方法是脚本的核心,可拆分为 6 个关键子流程:

子流程 1:打开登录页面并等待扫码登录
# 打开登录页面
self.driver.get("https://kyfw.12306.cn/otn/resources/login.html")

# 判断是否登录成功
while not self.is_element_exist('//a[@class="txt-primary underline"]'):
    # 循环等待用于扫码登录
    time.sleep(1)
  • driver.get():加载 12306 登录页面;
  • 循环调用is_element_exist校验登录成功标识元素(登录后出现的 “我的 12306” 类链接),每 1 秒检查一次,直到用户完成扫码登录,确保后续操作基于已登录状态。
子流程 2:跳转至车票查询页面
self.driver.find_element(By.XPATH, '//a[@class="txt-primary underline"]').click()
time.sleep(1)
  • 定位并点击登录成功后的跳转链接,进入车票预订页面;
  • 休眠 1 秒等待页面跳转完成,避免操作提前导致元素定位失败。
子流程 3:自动填写出发 / 到达站信息
# 定位出发地输入框,并输入站点名
self.driver.find_element(By.XPATH, '//input[@id="fromStationText"]').click()
self.driver.find_element(By.XPATH, '//input[@id="fromStationText"]').send_keys(self.from_st)
self.driver.find_element(By.XPATH, '//span[@class="ralign"]').click()
time.sleep(0.5)

# 定位目的地输入框,并输入站点名
self.driver.find_element(By.XPATH, '//input[@id="toStationText"]').click()
self.driver.find_element(By.XPATH, '//input[@id="toStationText"]').send_keys(self.to_st)
self.driver.find_element(By.XPATH, '//span[@class="ralign"]').click()
time.sleep(0.5)
  • 操作逻辑:点击输入框→输入站点名称→点击确认按钮;
  • 每个操作后休眠 0.5 秒,模拟人工操作节奏,避免触发反爬;
  • 注意:XPATH 定位需与 12306 页面 DOM 结构匹配,若页面更新需同步调整。
子流程 4:填写出发日期并查询车票
# 定位日期输入框,并输入对应的日期
self.driver.find_element(By.XPATH, '//input[@id="train_date"]').clear()
self.driver.find_element(By.XPATH, '//input[@id="train_date"]').send_keys(self.de_time)
time.sleep(0.5)

# 定位搜索按钮,并点击搜索
self.driver.find_element(By.XPATH, '//a[@id="query_ticket"]').click()
time.sleep(0.5)
  • clear():清空日期输入框默认值,避免残留内容影响输入;
  • send_keys():输入指定格式的出发日期(如 2025-09-01);
  • 点击 “查询车票” 按钮,加载符合条件的车次列表。
子流程 5:预订车票并选择乘车人
# 点击预定车票
self.driver.find_element(By.XPATH, '//a[text()="预订"]').click()
time.sleep(0.5)

# 选择乘车人
self.driver.find_element(By.XPATH, '//input[@title="设置为乘车人,按空格键进行操作"]').click()
time.sleep(0.5)
print('选择成功')

# 点击提交订单
self.driver.find_element(By.XPATH, '//a[text()="提交订单"]').click()
print('提交成功')
time.sleep(3)

# 确认订单(二维码提交)
self.driver.find_element(By.ID, 'qr_submit_id').click()
print('确认成功')
  • 定位 “预订” 按钮并点击,进入乘车人选择页面;
  • 选择预设的乘车人(需提前在 12306 账号中添加);
  • 提交订单并点击确认按钮,最终生成支付订单(需用户 15 分钟内完成支付)。
子流程 6:异常处理与提示
except Exception as e:
    print('================选票重试中================')

print('请在15分钟内支付订单')
time.sleep(60)
  • 捕获操作过程中的所有异常(如元素定位失败、页面加载超时等),打印重试提示;
  • 提示用户在 15 分钟内完成支付,休眠 60 秒保留页面供用户操作。

5. 主程序入口

if __name__ == '__main__':
    # 定义出发地
    from_station = '长沙'
    # 定义目的地
    to_station = '北京西'
    # 设置出行日期(最多只能设置15天内)
    departure_time = '2025-09-01'

    # 实例化类
    T = TrainTicketBot(from_station, to_station, departure_time)
    # 开始自动抢票
    T.check_ticket()
  • 定义脚本运行的核心参数(出发站、到达站、出发日期);
  • 实例化TrainTicketBot类并调用check_ticket方法启动抢票流程。

三、脚本优化与实战注意事项

1. 现有脚本的局限性

  • 未实现车次筛选:默认点击第一个 “预订” 按钮,无法指定车次、席别;
  • 无重试机制:仅捕获异常打印提示,未实现自动重新查询;
  • 定位方式脆弱:XPATH 依赖页面 DOM 结构,12306 页面更新后脚本会失效;
  • 未处理验证码:若登录过程中出现验证码,脚本会卡住。

2. 优化方向

(1)增加车次筛选功能
# 在check_ticket方法中,查询车票后添加车次筛选
def filter_train(self, train_num):
    # 定位所有车次行
    train_rows = self.driver.find_elements(By.XPATH, '//tbody[@id="queryLeftTable"]/tr')
    for row in train_rows:
        # 获取车次编号
        train_id = row.find_element(By.XPATH, './td[1]/div/div[1]/div/a').text
        if train_id == train_num:
            # 点击该车次的预订按钮
            row.find_element(By.XPATH, './td[last()]/a').click()
            return True
    return False
(2)实现循环抢票逻辑
def check_ticket(self):
    self.driver.get("https://kyfw.12306.cn/otn/resources/login.html")
    while not self.is_element_exist('//a[@class="txt-primary underline"]'):
        time.sleep(1)
    self.driver.find_element(By.XPATH, '//a[@class="txt-primary underline"]').click()
    time.sleep(1)
    
    # 循环抢票,直到成功
    while True:
        try:
            # 原有填写信息逻辑...
            # 新增车次筛选
            self.filter_train('G508')  # 指定车次
            # 原有选择乘车人、提交订单逻辑...
            break  # 成功后退出循环
        except Exception as e:
            print(f'抢票失败,重试中:{e}')
            time.sleep(2)  # 失败后休眠2秒重新查询

3. 实战安全注意事项

  • 遵守 12306 用户协议:自动化脚本可能违反平台规定,过度使用可能导致账号封禁;
  • 控制操作频率:避免短时间内高频次请求,建议将休眠时间设置为 1-3 秒;
  • 及时更新定位规则:12306 页面会不定期更新,需同步调整 XPATH/ID 等定位符;
  • 保护账号安全:脚本中避免硬编码账号密码,建议通过扫码登录方式操作。

四、总结

本文对 12306 自动抢票脚本的核心模块、代码逻辑进行了全面拆解,分析了脚本的设计思路与局限性,并给出了优化方向。该脚本本质是利用 Selenium 模拟人工操作,核心价值在于简化重复的购票流程,但在实际使用中需兼顾平台规则与反爬机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值