基于 Python 和 Selenium 的 铁路12306 自动化购票全解析

一、背景与技术选型

12306 作为全球最大的实时票务系统,日均处理数千万次请求,其反爬机制也在不断升级。有这还怕平时回家买不到票?本文将介绍如何通过 Python 和 Selenium 实现自动化购票,重点突破以下技术难点:

  • 反检测配置(隐藏自动化特征)
  • 动态元素处理(显式等待与动态定位)
  • 多场景交互(登录、查询、预订)
二、核心代码解析

1. 反检测配置(关键反爬策略)

options = Options()
# 移除自动化标识
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_argument('--disable-blink-features=AutomationsControlled')
# 关闭证书验证
options.add_argument('ignore-certificate-errors')
driver = webdriver.Chrome(options=options)
  • 技术原理:通过修改浏览器启动参数,移除navigator.webdriver属性等自动化特征,降低被 12306 识别的概率。

2. 登录模块(用户输入与二次验证)

def Longin():
    driver.get('https://kyfw.12306.cn/otn/resources/login.html')
    user = input("请输入用户名: ")
    pwd = getpass.getpass("请输入密码: ")  # 密码输入隐藏
    # 定位并输入用户名/密码
    nameuser = driver.find_element(By.XPATH, '//div/input[@id="J-userName"]')
    password = driver.find_element(By.XPATH, '//div/input[@id="J-password"]')
    nameuser.send_keys(user)
    password.send_keys(pwd)
    driver.find_element(By.XPATH, '//*[@id="J-login"]').click()
    # 二次验证(身份证后四位+短信验证码)
    code_id = input("请输入身份证后四位:")
    driver.find_element(By.XPATH, '//*[@id="verification_code"]').click()
    code = input("请输入验证码:")
    driver.find_element(By.XPATH, '//*[@id="code"]').send_keys(code)
    # 检查登录结果
    try:
        error_element = driver.find_element(By.XPATH, '//*[@id="message"]/p')
        if error_element.text == "用户名或密码错误":
            print("登录失败:请检查信息")
        else:
            print("登录成功")
            driver.find_element(By.XPATH, '//*[@id="link_for_ticket"]').click()
            Inquirer()
    except Exception as e:
        print(f"未找到错误提示:{e}")
  • 安全设计:使用getpass模块隐藏密码输入,避免敏感信息泄露。
  • 验证流程:支持身份证后四位 + 短信验证码的二次验证,符合 12306 最新登录逻辑。
  • 运行结果展示
  • 请输入用户名: 13800138000
    请输入密码: ········  # 输入时密码不可见
    请输入身份证后四位:1234
    验证码正在发送中,请耐心等待
    请输入验证码:56789
    登录成功

3. 查询模块(日期处理与车次提取)

def Inquirer():
    chufadi = input("请输入出发地:")
    mudidi = input("请输入目的地:")
    # 日期处理(默认当天,支持格式验证)
    current_date = datetime.now().strftime("%Y-%m-%d")
    user_input = input("输入出发日期(格式: YYYY-MM-DD,留空默认今日):")
    departure_date = current_date if not user_input else datetime.strptime(user_input, "%Y-%m-%d").strftime("%Y-%m-%d")
    # 更新日期输入框
    if departure_date != current_date:
        date_input = driver.find_element(By.XPATH, '//*[@id="train_date"]')
        date_input.clear()
        date_input.send_keys(departure_date)
    # 点击查询
    driver.find_element(By.XPATH, '//*[@id="query_ticket"]').click()
    # 提取车次信息(存在索引越界风险,需优化)
    list_Train = []
    for trin in range(20):
        try:
            dizhi = driver.find_element(By.XPATH, f'//*[@id="train_num_{trin}"]/div/strong')
            list_Train.append(dizhi.text)
            print(f"车次: {list_Train[trin]} | 出发地: {list_Train[trin+1]} | 到达时间: {list_Train[trin+2]}")
        except:
            break
  • 日期验证:使用datetime.strptime进行格式校验,确保输入合法。
  • 车次提取:通过循环遍历车次列表,动态获取车次信息(需注意索引越界问题)
  • 运行结果
  • 请输入出发地:北京
    请输入目的地:上海
    输入出发日期(格式: YYYY-MM-DD,留空默认今日):2025-05-20
    正在查询2025-05-20的车票,请稍后...
    
                    出发地                   目的地                   到达时间 
            G1    北京南       上海虹桥       08:00
    
                    出发地                   目的地                   到达时间 
            G3    北京南       上海虹桥       09:00
    
                    出发地                   目的地                   到达时间 
            G5    北京南       上海虹桥       10:00

4. 预订模块(时间匹配与订单提交)

def Get_ticket():
    # 提取所有车次的出发时间
    time_list = [driver.find_element(By.XPATH, f'//*[@id="train_num_{i}"]/div[3]/strong[1]').text 
                 for i in range(int(driver.find_element(By.XPATH, '//*[@id="trainum"]').text))]
    move_time = input("选择出发时间段(1/2/3):")
    wait = WebDriverWait(driver, 10)
    if move_time == '1':
        driver.find_element(By.XPATH, '//*[@id="cc_start_time"]/option[3]').click()
        accurate_time = input("输入目标时间(如12:00):")
        closest = get_closest_time(accurate_time, time_list)
        # 显式等待确保预订按钮可见
        wait.until(EC.visibility_of_element_located((By.XPATH, f'//a[@class="btn72" and contains(text(), "{closest}")]')))
        driver.find_element(By.XPATH, f'//a[@class="btn72" and contains(@onclick, "{closest}")]').click()
        # 提交订单
        driver.find_element(By.XPATH, '//*[@id="normalPassenger_0"]').click()  # 选择乘客
        driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()  # 提交订单
  • 时间匹配:使用get_closest_time函数计算最接近用户指定时间的车次,提升购票精准度。
  • 显式等待:通过WebDriverWait确保预订按钮加载完成,避免元素未找到错误。
  • 运行结果展示
  • 请输入出发时间段,
    1: 06:00--12:00
    2: 12:00--18:00
    3: 18:00--24:001
    输入准确时间,将会自动购买靠近该时间的车票(12:00)09:30
    最接近 09:30 的时间是: 09:00
    所有时间为 ['08:00', '09:00', '10:00']

三、代码优化与最佳实践

1. 反检测增强(应对 12306 最新策略)

# 通过CDP命令修改navigator.webdriver属性
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
    Object.defineProperty(navigator, 'webdriver', {
      get: () => undefined
    })
    """
})
  • 技术原理:直接修改浏览器环境,隐藏navigator.webdriver属性,绕过 12306 的自动化检测。

2. 动态元素处理(避免固定索引)

# 优化车次信息提取(使用动态定位)
trains = driver.find_elements(By.XPATH, '//div[contains(@id, "train_num_")]')
for train in trains:
    try:
        info = [elem.text for elem in train.find_elements(By.XPATH, './div/strong')]
        print(f"车次: {info[0]} | 出发地: {info[1]} | 到达时间: {info[2]}")
    except IndexError:
        continue
  • 优化点:使用动态元素定位,避免固定索引导致的越界错误。

3. 异常处理(提升稳定性)

# 添加异常捕获与重试机制
from selenium.common.exceptions import NoSuchElementException

def safe_click(by, value, timeout=10):
    try:
        wait = WebDriverWait(driver, timeout)
        element = wait.until(EC.element_to_be_clickable((by, value)))
        element.click()
    except NoSuchElementException:
        print(f"元素 {value} 未找到")
    except TimeoutException:
        print(f"等待元素 {value} 超时")
  • 作用:封装点击操作,处理元素未找到或超时异常,提高脚本鲁棒性。
四、风险提示与合规建议
  1. 法律风险

    • 自动化抢票可能违反 12306 用户协议,甚至涉嫌非法经营罪。
    • 建议仅用于学习用途,避免用于实际购票。
  2. 账号安全

    • 频繁自动化操作可能导致账号被封禁。
    • 避免在代码中存储敏感信息,如账号密码。
  3. 技术对抗

    • 12306 已推出防抢票专利,如 SVG 验证码、行为验证等。
    • 脚本需持续更新以应对反爬策略变化。
五、总结与扩展

本文介绍了基于 Selenium 的 12306 自动化购票实现,涵盖反检测配置、登录验证、车次查询、时间匹配等核心功能。建议结合以下方向进一步优化:

  1. 多线程与分布式:使用多线程提高查询效率,结合代理 IP 避免 IP 封禁。
  2. 图像识别:集成 OCR 技术自动识别验证码,降低人工干预。
  3. 候补购票:模拟 12306 官方候补逻辑,提升购票成功率。

六、总体代码展示(Al优化后)

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import time
from datetime import datetime
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import getpass

# ----------------------
# 浏览器反检测配置
# ----------------------
def create_chrome_options():
    options = Options()
    # 隐藏自动化特征
    options.add_experimental_option('excludeSwitches', ['enable-automation'])
    options.add_experimental_option('useAutomationExtension', False)
    options.add_argument('--disable-blink-features=AutomationsControlled')
    # 伪装用户代理(可替换为真实浏览器UA)
    options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36')
    # 其他实用配置
    options.add_argument('ignore-certificate-errors')
    options.add_argument('--disable-gpu')
    options.add_argument('--no-sandbox')
    options.add_argument('--headless')  #无头模式 注释这句 可以展示出购票 过程
    #不注释,大大缩短,购票时间
    return options

# ----------------------
# 登录模块
# ----------------------
def login(driver):
    try:
        driver.get('https://kyfw.12306.cn/otn/resources/login.html')
        wait = WebDriverWait(driver, 10)
        
        # 输入用户名和密码
        user = input("请输入用户名: ")
        pwd = getpass.getpass("请输入密码: ")
        
        # 定位并输入用户名
        username_input = wait.until(EC.presence_of_element_located((By.XPATH, '//div/input[@id="J-userName"]')))
        username_input.send_keys(user)
        
        # 定位并输入密码
        password_input = wait.until(EC.presence_of_element_located((By.XPATH, '//div/input[@id="J-password"]')))
        password_input.send_keys(pwd)
        
        # 点击登录按钮
        login_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="J-login"]')))
        login_button.click()
        
        # 二次验证:身份证后四位
        code_id = input("请输入身份证后四位: ")
        id_input = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/div[1]/div[4]/div[2]/div[1]/div/div[1]/input')))
        id_input.send_keys(code_id)
        
        # 点击获取短信验证码
        get_code_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="verification_code"]')))
        get_code_button.click()
        time.sleep(2)
        
        # 输入短信验证码
        code = input("请输入短信验证码: ")
        code_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="code"]')))
        code_input.send_keys(code)
        
        # 检查登录结果
        try:
            error_msg = wait.until(EC.visibility_of_element_located((By.XPATH, '//*[@id="message"]/p'))).text
            if "用户名或密码错误" in error_msg:
                print("登录失败:用户名、密码或验证码错误")
                return False
        except:
            print("登录成功!")
            # 跳转到车票查询页面
            ticket_link = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="link_for_ticket"]')))
            ticket_link.click()
            return True
    except Exception as e:
        print(f"登录过程中出现错误:{e}")
        return False

# ----------------------
# 车次查询模块
# ----------------------
def search_tickets(driver):
    try:
        wait = WebDriverWait(driver, 10)
        # 输入出发地和目的地
        from_station = input("请输入出发地: ")
        to_station = input("请输入目的地: ")
        
        # 定位出发地输入框
        from_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="fromStationText"]')))
        from_input.clear()
        from_input.send_keys(from_station)
        
        # 定位目的地输入框
        to_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="toStationText"]')))
        to_input.clear()
        to_input.send_keys(to_station)
        
        # 处理出发日期
        current_date = datetime.now().strftime("%Y-%m-%d")
        user_date = input("输入出发日期(格式: YYYY-MM-DD,留空默认今日): ")
        departure_date = current_date if not user_date else user_date
        
        # 更新日期输入框
        if departure_date != current_date:
            date_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="train_date"]')))
            date_input.clear()
            date_input.send_keys(departure_date)
        
        # 点击查询按钮
        search_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="query_ticket"]')))
        search_button.click()
        print(f"正在查询{departure_date}从{from_station}到{to_station}的车票...")
        time.sleep(3)  # 等待查询结果加载
        return departure_date
    except Exception as e:
        print(f"查询车次时出现错误:{e}")
        return None

# ----------------------
# 车票预订模块
# ----------------------
def book_ticket(driver, departure_date):
    try:
        wait = WebDriverWait(driver, 10)
        # 提取所有车次时间
        time_list = []
        train_elements = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//div[contains(@id, "train_num_")]')))
        for i, train in enumerate(train_elements):
            try:
                time_text = train.find_element(By.XPATH, './div[3]/strong[1]').text
                time_list.append(time_text)
            except:
                continue
        
        if not time_list:
            print("未找到可用车次!")
            return
        
        # 用户选择时间段
        move_time = input("请选择出发时间段(1:06:00-12:00,2:12:00-18:00,3:18:00-24:00): ")
        time_ranges = {
            '1': ('06:00--12:00', 3),
            '2': ('12:00--18:00', 4),
            '3': ('18:00--24:00', 5)
        }
        if move_time not in time_ranges:
            print("无效选择!")
            return
        
        # 选择时间段
        range_name, option_index = time_ranges[move_time]
        time_option = wait.until(EC.element_to_be_clickable((By.XPATH, f'//*[@id="cc_start_time"]/option[{option_index}]')))
        time_option.click()
        print(f"已筛选{range_name}的车次")
        
        # 输入目标时间并匹配最接近车次
        target_time = input("请输入目标时间(格式: HH:MM): ")
        closest_time = get_closest_time(target_time, time_list)
        print(f"最接近的车次时间:{closest_time}")
        
        # 等待预订按钮加载并点击
        book_button = wait.until(EC.element_to_be_clickable((By.XPATH, f'//a[@class="btn72" and contains(text(), "{closest_time}")]')))
        book_button.click()
        time.sleep(2)
        
        # 选择乘客(默认第一个乘客,需根据实际情况调整)
        passenger = wait.until(EC.element_to_be_clickable((By.XPATH, '//ul[@id="normal_passenger_id"]/li[1]/input')))
        passenger.click()
        
        # 提交订单(需手动处理可能的验证码或确认弹窗)
        submit_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@id="submitOrder_id"]')))
        submit_button.click()
        print("已提交订单,请尽快完成支付!")
    except Exception as e:
        print(f"预订车票时出现错误:{e}")

# ----------------------
# 时间匹配函数
# ----------------------
def get_closest_time(user_time, time_list):
    user_min = int(user_time[:2]) * 60 + int(user_time[3:])
    time_diffs = [(abs(int(t[:2])*60 + int(t[3:]) - user_min), t) for t in time_list]
    return min(time_diffs, key=lambda x: x[0])[1]

# ----------------------
# 主程序入口
# ----------------------
if __name__ == "__main__":
    options = create_chrome_options()
    driver = webdriver.Chrome(options=options)
    
    if login(driver):
        departure_date = search_tickets(driver)
        if departure_date:
            book_ticket(driver, departure_date)
    
    input("按回车键退出程序...")
    driver.quit()

作者原创

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options  # 导入Options操作类
import time
from datetime import datetime
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import getpass

# 获取当前日期(格式:YYYY-MM-DD)
current_date = datetime.now().strftime("%Y-%m-%d")

options = Options()
options.add_argument('--headless')  #无头模式
# 设置自动化特性扩展的关闭,防止被服务器检测到是由selenium驱动的
options.add_experimental_option('excludeSwitches', ['enable-automation'])

# 设置关闭自动化特性,防止被服务器检测到是由selenium驱动的
options.add_argument('--disable-blink-features=AutomationsControlled')

# 关闭证书报错
options.add_argument('ignore-certificate-errors')
# 启动 WebDriver(假设你使用的是 Chrome)  如果这里不进行传参数 就是有界面模式
driver = webdriver.Chrome(options = options)
# driver = webdriver.Chrome()


time.sleep(1)


def Longin():
    try:
        # 打开目标网页
        driver.get('https://kyfw.12306.cn/otn/resources/login.html')

        # 获取用户输入的账号和密码
        user = input("请输入用户名: ")
        # pwd = input("请输入密码: ")
        pwd = getpass.getpass("请输入密码: ")  # 输入时密码不会显示在屏幕上

        # 使用 XPath 定位用户名输入框并输入
        nameuser = driver.find_element(By.XPATH, '//div/input[@id="J-userName"]')
        time.sleep(1)
        nameuser.send_keys(user)

        # 定位密码输入框并输入
        password = driver.find_element(By.XPATH, '//div/input[@id="J-password"]')
        time.sleep(1)
        password.send_keys(pwd)

        # 登录按钮点击
        driver.find_element(By.XPATH, '//*[@id="J-login"]').click()

        # 后续代码保持不变
        code_id = input("请输入身份证后四位:")
        id_cord = driver.find_element(By.XPATH, '/html/body/div[1]/div[4]/div[2]/div[1]/div/div[1]/input')
        id_cord.send_keys(code_id)
        print("验证码正在发送中,请耐心等待")
        time.sleep(1)
        driver.find_element(By.XPATH, '//*[@id="verification_code"]').click()
        time.sleep(1)
        id_code = driver.find_element(By.XPATH, '//*[@id="code"]')
        code = input("请输入验证码:")
        id_code.send_keys(f"{code}")

        try:
            error_element = driver.find_element(By.XPATH, '//*[@id="message"]/p')
            if error_element.text == "用户名或密码错误":
                print("密码,用户名,验证码错误,请检查")
            else:
                print("登录成功")
                time.sleep(2)
                driver.find_element(By.XPATH, '//*[@id="link_for_ticket"]').click()
                time.sleep(2)
                driver.find_element(By.XPATH, '//*[@id="sureClick"]')
                Inquirer()
        except Exception as e:
            print(f"未找到错误提示元素: {e}")

    except  Exception as e:
        print("程序运行发生错误", e)

def Inquirer():
    try:
        chufadi = input("请输入出发地:")
        # 获取出发地输入框
        from_station_input = driver.find_element(By.XPATH, '//*[@id="fromStationText"]')
        # 清空输入框
        from_station_input.clear()
        # 输入出发地
        from_station_input.send_keys(chufadi)

        mudidi = input("请输入目的地:")
        end_station_input = driver.find_element(By.XPATH, '//*[@id="toStationText"]')
        end_station_input.clear()
        end_station_input.send_keys(mudidi)
        from datetime import datetime, timedelta

        try:
            # 获取当前日期
            current_date = datetime.now().strftime("%Y-%m-%d")

            # 获取用户输入
            user_input = input("不输入默认获取当日,回车跳过输入,输入出发时间格式(2025-5-20):")

            # 处理用户输入
            if not user_input.strip():  # 输入为空
                departure_date = current_date
                print(f"未输入日期,将查询今日({departure_date})车票")
            else:
                try:
                    # 验证并格式化日期
                    parsed_date = datetime.strptime(user_input, "%Y-%m-%d")
                    departure_date = parsed_date.strftime("%Y-%m-%d")
                except ValueError:
                    print("警告:输入日期格式不正确,将使用默认日期")
                    departure_date = current_date

            # 如果不是查询当日,需要更新日期输入框
            if departure_date != current_date:
                date_input = driver.find_element(By.XPATH, '//*[@id="train_date"]')
                date_input.clear()
                date_input.send_keys(departure_date)

            # 点击查询按钮(合并重复逻辑)
            query_button = driver.find_element(By.XPATH, '//*[@id="query_ticket"]')
            query_button.click()
            print(f"正在查询{departure_date}的车票,请稍后...")

            list_Train = []
            for trin in range(0, 20):
                dizhi = driver.find_element(By.XPATH, f'//*[@id="train_num_{trin}"]/div/strong')
                time.sleep(1)
                list_Train.append(dizhi.text)
                print(f"""
                出发地                   目的地                   到达时间 
        {list_Train[trin]}    {list_Train[trin+1]}       {list_Train[trin+2]}
                """)

        except Exception as e:
            print(f"程序运行发生错误,在输入日期 {e}")

    except Exception as e:
        print("程序运行发生错误,在输入地点", e)

#下面这个会确定元素加载完才会进行下一步

def Get_ticket():
    time_list = []
    chechi_number = driver.find_element(By.XPATH, '//*[@id="trainum"]')
    chechi_number = int(chechi_number.text)
    for i in range(chechi_number):
        time_list.append(driver.find_element(By.XPATH, f'//*[@id="train_num_{i}"]/div[3]/strong[1]').text)

    move_time = input("请输入出发时间段,\n1: 06:00--12:00\n2: 12:00--18:00\n3: 18:00--24:00")

    # 创建显式等待对象
    wait = WebDriverWait(driver, 10)

    if move_time == '1':
        """
        //*[@id="cc_start_time"]/option[*]  选着时间段 
        #这个是通过固定时间选定这个预订标签  onclick 这个下面的时间 选着这个标签 
        //a[@class="btn72" and contains(@onclick, '21:02')]
        """
        driver.find_element(By.XPATH, '//*[@id="cc_start_time"]/option[3]').click()
        accurate_time = input("输入准确时间,将会自动购买靠近该时间的车票(12:00)")
        closest = get_closest_time(accurate_time, time_list)
        print(f"最接近 {accurate_time} 的时间是: {closest}")
        print('所有时间为', str(time_list))

        # 添加显式等待
        wait.until(
            EC.visibility_of_element_located((By.XPATH, f'//a[@class="btn72" and contains(text(), "{closest}")]')))

        # 点击预定按钮
        driver.find_element(By.XPATH, f'//a[@class="btn72" and contains(@onclick, "{closest}")]').click()
        time.sleep(1)
        driver.find_element(By.XPATH, '//*[@id="normalPassenger_0"]').click()  # 点击坐车人按钮
        driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_cancel"]').click()  # 点击取消按钮
        driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()  # 点击提交订单按钮

    if move_time == '2':
        driver.find_element(By.XPATH, '//*[@id="cc_start_time"]/option[4]').click()
        accurate_time = input("输入准确时间,将会自动购买靠近该时间的车票(12:00)")
        closest = get_closest_time(accurate_time, time_list)
        print(f"最接近 {accurate_time} 的时间是: {closest}")
        print('所有时间为', str(time_list))

        # 添加显式等待
        wait.until(
            EC.visibility_of_element_located((By.XPATH, f'//a[@class="btn72" and contains(text(), "{closest}")]')))

        # 点击预定按钮
        driver.find_element(By.XPATH, f'//a[@class="btn72" and contains(@onclick, "{closest}")]').click()
        time.sleep(1)
        driver.find_element(By.XPATH, '//*[@id="normalPassenger_0"]').click()  # 点击坐车人按钮
        driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_cancel"]').click()  # 点击取消按钮
        driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()  # 点击提交订单按钮

    if move_time == '3':
        driver.find_element(By.XPATH, '//*[@id="cc_start_time"]/option[5]').click()
        accurate_time = input("输入准确时间,将会自动购买靠近该时间的车票(12:00)")
        closest = get_closest_time(accurate_time, time_list)
        print(f"最接近 {accurate_time} 的时间是: {closest}")
        print('所有时间为', str(time_list))

        # 添加显式等待
        wait.until(
            EC.visibility_of_element_located((By.XPATH, f'//a[@class="btn72" and contains(text(), "{closest}")]')))

        # 点击预定按钮
        driver.find_element(By.XPATH, f'//a[@class="btn72" and contains(@onclick, "{closest}")]').click()
        time.sleep(1)
        driver.find_element(By.XPATH, '//*[@id="normalPassenger_0"]').click()  # 点击坐车人按钮
        driver.find_element(By.XPATH, '//*[@id="dialog_xsertcj_cancel"]').click()  # 点击取消按钮
        driver.find_element(By.XPATH, '//*[@id="submitOrder_id"]').click()  # 点击提交订单按钮

def get_closest_time(user_time, time_list):
    user_minutes = int(user_time[:2]) * 60 + int(user_time[3:])
    time_diffs = [(abs(int(t[:2]) * 60 + int(t[3:]) - user_minutes), t) for t in time_list]
    return min(time_diffs)[1]


if __name__ == '__main__':
    Longin()

# 等待一段时间以观察结果
# time.sleep()
input("回车结束")
# 关闭浏览器
driver.quit()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智极Hub

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值