当我准备出门时,发现了......我可以用Python实现12306自动买票

前言

不知道大家有没有之前碰到这样的情况,打算去某一个地方当你规划好了时间准备去买票的时候,你想要的那一列往往没有你想要的票了,尤其是国庆七天假和春节半月假,有时候甚至买不到规定计划时间内的票,真的是太烦躁了

为此我钻研了一下,现在科技如此发达,想要实现自动化还是比较简单的

1.导入需要的模块

import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

2.初始化WebDriver:

driver = webdriver.Chrome()  # 选择合适的浏览器驱动,这里以Chrome为例

3.打开12306网站:

driver.get('https://www.12306.cn')

4.登录12306账号:

首先手动登录一次,然后在浏览器中的开发者工具中找到登录请求的相关信息,提取出关键参数(比如cookies、token等),可以使用工具库来自动提取这些参数。

使用Python的requests库等发送该登录请求,将提取到的关键参数作为请求的header或body发送过去,模拟登录。

5.进入车票查询页面:

# 这里可能需要等待一段时间,直到页面加载完成
# 可以使用WebDriverWait等待特定的元素加载完成
wait = WebDriverWait(driver, 10)  # 设置等待时间为10秒
query_input = wait.until(EC.presence_of_element_located((By.ID, 'query_input')))
query_input.clear()
query_input.send_keys('出发地点')

上述代码将输入出发地点,你需要根据自己的需求修改。

6.查询车票:

search_btn = driver.find_element_by_id('search_btn')
search_btn.click()

# 这里可能需要等待一段时间,直到查询结果加载完成
# 同样可以使用WebDriverWait等待特定的元素加载完成

7.选择车次和座位:

train_btn = driver.find_element_by_id('train_btn')
train_btn.click()

# 这里可能需要等待一段时间,直到车次详情加载完成

seat_type = driver.find_element_by_id('seat_type')
seat_type.send_keys('座位类型')

buy_btn = driver.find_element_by_id('buy_btn')
buy_btn.click()

上述代码将选择指定的座位类型,你需要根据自己的需求修改。

8.填写乘客信息和提交订单:

passenger_name = driver.find_element_by_id('passenger_name')
passenger_name.send_keys('乘客姓名')

id_number = driver.find_element_by_id('id_number')
id_number.send_keys('乘客身份证号码')

# 填写其他乘客信息,如果有多个乘客

submit_btn = driver.find_element_by_id('submit_btn')
submit_btn.click()

上述代码将填写乘客的姓名、身份证号码等信息,你需要根据自己的需求修改。

9.处理验证码:

12306网站可能会出现验证码,你需要使用图像处理库(如PIL)来处理验证码图片并自动识别验证码。

如果遇到验证码,你可以通过人工干预或使用一些自动化技术(如OCR)处理,以便自动填写验证码。

10.确认订单和支付:

confirm_btn = driver.find_element_by_id('confirm_btn')
confirm_btn.click()

# 这里可能需要等待一段时间,直到支付页面加载完成

# 在该页面处理支付,根据你使用的支付方式进行自动化支付

以上只是一个基本的框架,实际实现可能需要根据12306网站的更新和变化进行相应的调整

那么根据具体时间2023年8月10号为例子,我们来具体操作一下,以下是具体源码:

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from config import Config
from selenium.webdriver.common.keys import Keys
import time
import select
 
# 用抛出异常来判断一个元素存不存在太慢了,需要等5秒钟
# def isElementExist(ele):
#     flag = True
#     result = EC.presence_of_element_located((By.XPATH, '//tbody[@id="queryLeftTable"]/tr[1]/td[13]/a'))
#     try:
#         # ele.find_element(by=By.CLASS_NAME, value='btn72')
#         result(ele)
#         return flag
#     except:
#         flag = False
#         return flag
 
 
def isElementExist(driver):
    flag=True
    ele = driver.find_elements(by=By.CLASS_NAME, value='btn72')
    if len(ele) == 0:
        flag = False
        return flag
    if len(ele) == 1:
        return flag
    else:
        flag = False
        return flag
 
 
def get_ticket(conf, driver, url):
    # 过网站检测,没加这句的话,账号密码登录时滑动验证码过不了,但二维码登录不受影响
    driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """Object.defineProperty(navigator, 'webdriver', {
          get: () => undefined})"""})
    driver.maximize_window()
    driver.get(url)
    # 最多等待5秒使页面加载进来,隐式等待
    driver.implicitly_wait(5)
 
    # 获取并点击右上角登录按钮
    login = driver.find_element(by=By.ID, value='J-btn-login')
    login.click()
    driver.implicitly_wait(10)
 
    # 账号密码登录
    username_tag = driver.find_element(by=By.ID, value='J-userName')
    username_tag.send_keys(conf.username)
    password_tag = driver.find_element(by=By.ID, value='J-password')
    password_tag.send_keys(conf.password)
    login_now = driver.find_element(by=By.ID, value='J-login')
    login_now.click()
    time.sleep(20)
 
    # # 过滑动验证码
    # picture_start = driver.find_element(by=By.ID, value='nc_1_n1z')
    # # 移动到相应的位置,并左键鼠标按住往右边拖
    # ActionChains(driver).move_to_element(picture_start).click_and_hold(picture_start).move_by_offset(300, 0).release().perform()
    #
    #
    # # 扫码登录
    # scan_QR = driver.find_element(by=By.XPATH, value='//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a')
    # scan_QR.click()
    # driver.implicitly_wait(10)
 
 
    # 点提示框
    # driver.find_element(by=By.XPATH, value='//div[@class="dzp-confirm"]/div[2]/div[3]/a').click()
    # driver.implicitly_wait(5)
 
    # 点击车票预订跳转到预订车票页面
    driver.find_element(by=By.XPATH, value='//*[@id="link_for_ticket"]').click()
    driver.implicitly_wait(10)
 
    # 输入出发地和目的地信息
    # 出发地
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').click()
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').clear()
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').send_keys(conf.fromstation)
    time.sleep(1)
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').send_keys(Keys.ENTER)
 
    # 目的地
    destination_tag = driver.find_element(by=By.XPATH, value='//*[@id="toStationText"]')
    destination_tag.click()
    destination_tag.clear()
    destination_tag.send_keys(conf.destination)
    time.sleep(1)
    destination_tag.send_keys(Keys.ENTER)
    driver.implicitly_wait(5)
 
    # 出发日期
    date_tag = driver.find_element(by=By.XPATH, value='//*[@id="train_date"]')
    date_tag.click()
    date_tag.clear()
    date_tag.send_keys(conf.date)
    time.sleep(1)
    query_tag = driver.find_element(by=By.XPATH, value='//*[@id="query_ticket"]')
 
    start = time.time()
 
    while True:
        driver.implicitly_wait(5)
        # 点击查询
        driver.execute_script("$(arguments[0]).click()", query_tag)
 
        # 判断页面中有没有“预订”按钮,如果没有预订按钮就不断查询直到车票开售
        if not isElementExist(driver):
            # 车票处于待开售状态
            print(f"15点30分起售,现在是{time.strftime('%H:%M:%S', time.localtime())},还未开始售票")
            # 每隔两分钟刷新一次,否则3分钟内无购票操作12306系统会自动登出
            if time.time() - start >= 120:
                driver.refresh()
                start = time.time()
            # 延时1秒防止过于快速地点击导致查询超时,当然偶尔还是会出现超时现象,不过超时也没关系,一般等待6秒之后就会继续自动查询
            time.sleep(1)
            continue
 
        # 获取所有车票
        tickets = driver.find_elements(by=By.XPATH, value='//*[@id="queryLeftTable"]/tr')
        # 每张车票有两个tr,但是第二个tr没什么用
        tickets = [tickets[i] for i in range(len(tickets) - 1) if i % 2 == 0]
        #print(tickets)
        for ticket in tickets:
            # 如果车票的车次等于想要的车次并且硬卧的状态不是候补则点击预订
            #if ticket.find_element(by=By.CLASS_NAME,value='cdz').text== conf.fromstation:
                #print(ticket.find_element(by=By.CLASS_NAME,value='number').text)
                # value = '//td[8]'表示硬卧,td[10]表示硬座
            if ticket.find_element(by=By.CLASS_NAME,value='number').text == conf.trainnumber and ticket.find_element(by=By.XPATH, value='//td[8]').text != "候补":
                # 点击预订
                #print(ticket.find_element(by=By.CLASS_NAME,value='cdz').text)
                #time.sleep(1)
                ticket.find_element(by=By.CLASS_NAME, value='btn72').click()
                # 这里之后就不能继续使用ticket.find_element()了,因为页面进行了跳转,会出现stale element reference: element is not attached to the page document的错误
                # 我们可以使用driver.find_element()
                # 选择乘车人,如果是学生,则需要确认购买学生票
                driver.find_element(by=By.XPATH, value='//*[@id="normalPassenger_0"]').click()
                # 点击确认购买学生票,如果不是学生,把这行注释了就行
                #driver.find_element(by=By.XPATH, value='//*[@id="dialog_xsertcj_ok"]').click()
                # 第二个乘车人
                # driver.find_element(by=By.XPATH, value='//*[@id="normalPassenger_1"]').click()
                # 如果第二个乘车人也是学生,则需要点击确认第二个人也购买学生票
                # driver.find_element(by=By.XPATH, value='//*[@id="dialog_xsertcj_ok"]').click()
                # 提交订单
                driver.find_element(by=By.XPATH, value='//*[@id="submitOrder_id"]').click()
                # 选座  F座
                #time.sleep(1)
                #move = driver.find_element(By.ID, value='1F')
                #ActionChains(driver).move_to_element(move).perform()
                # time.sleep(1)
                #这里直接使用id和xpath定位不到,所以直接加上他的路径,可以不用这么长,但是懒得删
                driver.find_element(by=By.XPATH, value='//html/body/div[5]/div/div[5]/div[1]/div/div[2]/div[2]/div[3]/div[2]/div[2]/ul[2]/li[2]/a[@id="1F"]').click()
                # 确认提交订单,然后这里和上面是一样的
                driver.find_element(by=By.XPATH, value='//html/body/div[5]/div/div[5]/div[1]/div/div[2]/div[2]/div[8]/a[2][@id="qr_submit_id"]').click()
                print(f"{conf.trainnumber}次列车抢票成功,请尽快在10分钟内支付!")
                return
 
 
if __name__ == '__main__':
    # 有关车票的配置信息保存在该类里
    # 请事先在config.py里填好相关信息
    conf = Config()
 
    url = 'https://www.12306.cn/index/'
 
    # chromedriver.exe版本为104,可以根据自己浏览器版本重新下载chromedriver.exe替换
    # chromedriver.exe下载地址:http://chromedriver.storage.googleapis.com/index.html
    # s = Service(r'chromedriver.exe')
    driver = webdriver.Chrome()
    get_ticket(conf, driver, url)
    time.sleep(10)
    driver.quit()

有问题欢迎留言~~~~

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/67888.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JVM】 垃圾回收篇——自问自答(1)

Q什么是垃圾: 运行程序中,没用任何指针指向的对象。 Q为什么需要垃圾回收? 内存只分配,不整理回收,迟早会被消耗完。 内存碎片的整理,为新对象腾出空间 没有GC程序无法正常进行。 Q 哪些区域有GC&#…

爬虫013_函数的定义_调用_参数_返回值_局部变量_全局变量---python工作笔记032

然后再来看函数,可以避免重复代码 可以看到定义函数以及调用函数

Linux命令200例:mount将文件系统挂载到指定目录下(常用)

🏆作者简介,黑夜开发者,全栈领域新星创作者✌。CSDN专家博主,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 &…

出现raise NotImplementedError报错

在学习《动手学深度学习》时,实现下面代码时,报出raise NotImplementedError错误。 import collections import torch from d2l import torch as d2l import math from torch import nnclass Seq2SeqEncoder(d2l.Encoder):def __init__(self,vocab_size,…

[虚幻引擎] UE DTBase64 插件说明 使用蓝图对字符串或文件进行Base64加密解密

本插件可以在虚幻引擎中使用蓝图对字符串,字节数组,文件进行Base64的加密和解密。 目录 1. 节点说明 String To Base64 Base64 To String Binary To Base64 Base64 To Binary File To Base64 Base64 To File 2. 案例演示 3. 插件下载 1. 节点说…

【vim 学习系列文章 4 - vim与系统剪切板之间的交互】

文章目录 背景1.1.1 vim支持clipboard 检查1.1.2 vim的寄存器 上篇文章:【vim 学习系列文章 3 - vim 选中、删除、复制、修改引号或括号内的内容】 背景 从vim中拷贝些文字去其它地方粘贴,都需要用鼠标选中vim的文字后,Ctrlc、Ctrlv&#x…

自定义注解(Annontation)

目录 1.注解定义 2.元注解定义 3. 自定义注解(自定义的注解名称相同的会覆盖原注解) 4.Annotation架构(元注解参数介绍) 1.注解定义 注解是用来将任何的信息或元数据(metadata)与程序元素(类…

Leetcode.1289 下降路径最小和 II

题目链接 Leetcode.1289 下降路径最小和 II rating : 1697 题目描述 给你一个 n x n 整数矩阵 g r i d grid grid ,请你返回 非零偏移下降路径 数字和的最小值。 非零偏移下降路径 定义为:从 g r i d grid grid 数组中的每一行选择一个数字&#xff…

ORACLE行转列、列转行实现方式及案例

ORACLE行转列、列转行实现方式及案例 行转列案例方式1.PIVOT方式2.MAX和DECODE方式3.CASE WHEN和GROUP BY 列转行案例方式1.UNPIVOT方式2.UNION ALL 行转列 案例 假设我们有一个名为sales的表,其中包含了产品销售数据。表中有三列:product(…

windows为nginx添加定时任务(开机延迟启动)

windows开机启动任务 调用定时任务管理器选中windows创建基本任务设置名称和描述设置触发器 并且添加个延迟触发设置操作设置条件配置设置 调用定时任务管理器 winr 输入 taskschd.msc回车 选中windows创建基本任务 设置名称和描述 设置触发器 并且添加个延迟触发 设置操作 …

【uniapp】 软键盘弹出后fixed定位被顶上去问题

问题描述 当手机设计的导航栏为fixed定位上去时&#xff0c;输入框获取焦点就会把顶部自定义的导航栏顶到上面去&#xff0c;如下图所示 解决办法 输入框设置 :adjust-position“false” <input type"text" :adjust-position"false" focus"i…

算法基础简介

目录 1、递归 2、二分查找 3、排序算法 分类 3.1、冒泡排序 3.2、选择排序 3.3、插入排序 3.4、希尔排序(高级插入排序) 3.5、归并排序 3.6、快速排序 核心思想 具体步骤 代码实现 3.7、堆排序 3.8、计数排序 3.9、桶排序 3.10、基数排序 4、字符串匹…

【80天学习完《深入理解计算机系统》】第三天 2.3 整数运算【正负溢出】【运算的溢出】【类型转换的二进制扩展】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

数据库的约束 详解

一、约束的概述 1.概念:约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 2&#xff0e;目的:保证数据库中数据的正确、有效性和完整性。 3.分类: 约束描述关键字非空约束限制该字段的数据不能为nullNOT NULL唯一约束保证该字段的所有数据都是唯一、不…

全球飞机电磁阀总体规模分析

电磁阀是一种液压管路的电磁装置&#xff0c;通过使用电流产生磁场&#xff0c;从而驱动螺线管&#xff0c;控制阀中流体的流动。电磁阀作为流体控制自动化系统的执行器之一&#xff0c;有着结构紧凑、尺寸小、重量轻、密封良好、维修简便和可靠性高、节能降耗的特点&#xff0…

如何安全变更亚马逊收款账户?

有太多的卖家想知道如何安全变更亚马逊收款账户&#xff0c;因为更改了第三方收款账户可能会导致二次视频认证或者增强视频。真的是这样吗&#xff1f; 其实不推荐亚马逊店铺正常运营之后去变更信用卡&#xff0c;收款账户等重要资料的&#xff0c;因为玩黑科技的卖家也真的多…

[C++ 网络协议] 套接字

目录 1. 套接字 1.1 在Linux平台下构建套接字 1.1.1 用于接听的套接字(服务器端套接字) 1.1.2 用于发送请求的套接字(客户端套接字) 1.2 在Windows平台下构建套接字 1.2.1 Winsock的初始化 1.2.2 用于接听的套接字(服务器端套接字) 1.2.3 用于发送请求的套接字(客户端套…

vue+neo4j(neo4j desktop安装和使用)

vueneo4j&#xff08;neo4j desktop安装和使用&#xff09; 本文目录 vueneo4j&#xff08;neo4j desktop安装和使用&#xff09;官网下载安装基本使用创建项目新增数据库连接数据库 使用cypher构建简单知识图谱创建节点创建关系删除节点及关系查询节点和关系 数据导出为json文…

Stable Diffusion - 俯视 (from below) 拍摄的人物图像 LoRA 与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132192139 图像来自 哥特风格 LoRA 俯视 LoRA&#xff0c;提升视觉冲击力&#xff0c;核心配置 <lora:view_from_below:0.6>,(from below,…

JVM工作的总体机制概述

JDK、JRE、JVM关系回顾 JVM&#xff1a;Java Virtual Machine&#xff0c;翻译过来是Java虚拟机JRE&#xff1a;Java Runtime Environment&#xff0c;翻译过来是Java运行时环境 JREJVMJava程序运行时所需要的类库JDK&#xff1a;Java Development Kits&#xff0c;翻译过来是…