一、工具适配环境与安装准备
二、基础配置:登录与服务器同步

三、核心功能设置:精准配置购票需求
四、进阶功能调试:提升购票成功率
五、运行与状态监控
适用场景分析
- 出行高峰期购票:春节、国庆等节假日,热门线路(如跨省高铁、返乡直达车次)车票需求旺盛,手动抢票成功率低,工具的自动化查询、多线程提交功能可大幅提升抢购效率。
- 多维度购票需求:需要为多名乘客(如家庭出行、同事结伴)购票,或需要同时关注多个车次、多种席别(如既要二等座也要硬卧),工具的批量配置功能可减少重复操作,避免遗漏。
- 候补购票监控:目标车次售罄后,手动监控候补订单耗时耗力,工具可 24 小时自动监控候补进展,一旦有退票或新增车票,立即完成候补提交。
- 时间紧张人群:上班族、学生党等没有充足时间蹲点抢票,工具的定时抢票、自动支付功能可解放双手,无需时刻关注购票页面,不影响日常工作和学习。
相关软件教程已打包整理至网盘,如需获取完整软件教程及配置细节,私信我备注文章标题即可领取。
import time
import datetime
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException, WebDriverException
class TrainTicketAssistant:
"""12306购票辅助工具,实现车次查询、候补监控、购票请求提交等功能"""
def __init__(self, driver_path=None):
"""
初始化浏览器驱动
:param driver_path: 浏览器驱动路径(如ChromeDriver路径),未指定则使用系统环境变量中的驱动
"""
self.driver = None
self.wait = None
self.init_driver(driver_path)
def init_driver(self, driver_path):
"""初始化selenium浏览器驱动"""
try:
# 配置Chrome浏览器选项
chrome_options = webdriver.ChromeOptions()
# 禁用浏览器弹窗、图片加载优化(提升运行速度)
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option("useAutomationExtension", False)
chrome_options.add_argument("–disable-blink-features=AutomationControlled")
chrome_options.add_argument("–disable-images")
# 初始化驱动
if driver_path:
self.driver = webdriver.Chrome(executable_path=driver_path, options=chrome_options)
else:
self.driver = webdriver.Chrome(options=chrome_options)
# 设置隐式等待和显式等待
self.driver.implicitly_wait(10)
self.wait = WebDriverWait(self.driver, 15)
# 最大化浏览器窗口
self.driver.maximize_window()
except WebDriverException as e:
print(f"浏览器驱动初始化失败:{str(e)}")
raise
def sync_server_time(self):
"""同步12306服务器时间,确保购票时间精准"""
try:
# 调用12306接口获取服务器时间(示例接口,实际需以官方为准)
response = requests.get("https://kyfw.12306.cn/otn/")
server_time = response.headers.get("Date")
if server_time:
# 转换为本地时间
server_datetime = datetime.datetime.strptime(server_time, "%a, %d %b %Y %H:%M:%S GMT")
local_datetime = server_datetime + datetime.timedelta(hours=8) # 转换为北京时间
print(f"已同步12306服务器时间:{local_datetime.strftime('%Y-%m-%d %H:%M:%S')}")
return local_datetime
else:
print("无法获取服务器时间,使用本地时间替代")
return datetime.datetime.now()
except Exception as e:
print(f"时间同步失败:{str(e)}")
return datetime.datetime.now()
def login_12306(self, username, password):
"""
模拟12306登录(注:实际12306有滑块/验证码验证,需手动完成)
:param username: 12306账号
:param password: 12306密码
"""
try:
# 打开12306登录页
self.driver.get("https://kyfw.12306.cn/otn/resources/login.html")
# 切换到账号密码登录
self.wait.until(EC.element_to_be_clickable((By.XPATH, '//a[@class="login-hd-account"]'))).click()
# 输入账号
username_input = self.wait.until(EC.visibility_of_element_located((By.ID, "J-userName")))
username_input.clear()
username_input.send_keys(username)
# 输入密码
password_input = self.driver.find_element(By.ID, "J-password")
password_input.clear()
password_input.send_keys(password)
print("请手动完成滑块验证/验证码验证,完成后点击登录按钮")
# 等待用户手动完成验证并登录,超时120秒
WebDriverWait(self.driver, 120).until(
EC.url_contains("https://kyfw.12306.cn/otn/index/initMy12306")
)
print("12306登录成功")
except TimeoutException:
print("登录超时,请检查操作是否及时")
raise
except NoSuchElementException as e:
print(f"登录页面元素未找到:{str(e)}")
raise
def query_trains(self, from_station, to_station, date):
"""
查询指定条件的车次信息
:param from_station: 出发站(如"北京西")
:param to_station: 到达站(如"上海虹桥")
:param date: 出行日期(格式:YYYY-MM-DD)
:return: 车次信息列表
"""
try:
# 打开车票查询页面
self.driver.get("https://kyfw.12306.cn/otn/leftTicket/init")
# 输入出发站
from_input = self.wait.until(EC.visibility_of_element_located((By.ID, "fromStationText")))
from_input.click()
from_input.clear()
from_input.send_keys(from_station)
# 选择第一个匹配的站点(需等待下拉框加载)
self.wait.until(EC.visibility_of_element_located((By.XPATH, '//div[@class="cdz-list"]/ul/li[1]'))).click()
# 输入到达站
to_input = self.driver.find_element(By.ID, "toStationText")
to_input.click()
to_input.clear()
to_input.send_keys(to_station)
self.wait.until(EC.visibility_of_element_located((By.XPATH, '//div[@class="cdz-list"]/ul/li[1]'))).click()
# 选择出行日期
date_input = self.driver.find_element(By.ID, "train_date")
date_input.clear()
date_input.send_keys(date)
# 点击查询按钮
self.driver.find_element(By.ID, "query_ticket").click()
# 等待车次列表加载
train_list = self.wait.until(EC.visibility_of_element_located((By.ID, "queryLeftTable")))
trains = train_list.find_elements(By.TAG_NAME, "tr")
# 解析车次信息
train_info_list = []
for train in trains:
try:
train_no = train.find_element(By.CLASS_NAME, "number").text
start_time = train.find_element(By.CLASS_NAME, "start-time").text
arrive_time = train.find_element(By.CLASS_NAME, "arrive-time").text
# 席别余票信息(示例,实际需解析更多席别)
second_seat = train.find_element(By.XPATH, './/td[4]').text
train_info = {
"车次": train_no,
"出发时间": start_time,
"到达时间": arrive_time,
"二等座余票": second_seat if second_seat != "" else "无票"
}
train_info_list.append(train_info)
except NoSuchElementException:
continue
print(f"查询到{len(train_info_list)}趟符合条件的车次")
for info in train_info_list:
print(info)
return train_info_list
except Exception as e:
print(f"车次查询失败:{str(e)}")
return []
def monitor_wait_ticket(self, from_station, to_station, date, target_train_no):
"""
监控指定车次的候补/余票状态
:param from_station: 出发站
:param to_station: 到达站
:param date: 出行日期
:param target_train_no: 目标车次(如"G123")
"""
print(f"开始监控车次{target_train_no}的余票状态,出行日期:{date}")
while True:
try:
# 循环查询车次信息
train_list = self.query_trains(from_station, to_station, date)
target_train = None
for train in train_list:
if train["车次"] == target_train_no:
target_train = train
break
if target_train:
if target_train["二等座余票"] != "无票":
print(f"检测到车次{target_train_no}有可购票源:{target_train}")
# 可扩展:自动点击购票按钮提交订单
break
else:
print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} – 车次{target_train_no}暂无余票,继续监控…")
else:
print(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} – 未查询到车次{target_train_no},继续监控…")
# 每5秒查询一次(避免频繁请求被风控)
time.sleep(5)
except Exception as e:
print(f"监控过程异常:{str(e)}")
time.sleep(5)
def close(self):
"""关闭浏览器驱动"""
if self.driver:
self.driver.quit()
print("浏览器已关闭")
# 主函数示例
if __name__ == "__main__":
# 初始化购票辅助工具(若驱动未配置环境变量,需传入driver_path,如:driver_path="C:/chromedriver.exe")
assistant = TrainTicketAssistant()
try:
# 同步服务器时间
assistant.sync_server_time()
# 登录12306(替换为你的账号密码,需手动完成验证码验证)
assistant.login_12306("你的12306账号", "你的12306密码")
# 查询车次(示例:北京西→上海虹桥,2026-02-10)
assistant.query_trains("北京西", "上海虹桥", "2026-02-10")
# 监控指定车次候补状态(示例:监控G1次列车)
assistant.monitor_wait_ticket("北京西", "上海虹桥", "2026-02-10", "G1")
except Exception as e:
print(f"程序运行异常:{str(e)}")
finally:
# 关闭浏览器
assistant.close()

