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

news2024/10/7 0:27:47

前言

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

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

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()

有问题欢迎留言~~~~

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据分析-python学习 (1)numpy相关

内容为:https://juejin.cn/book/7240731597035864121的学习笔记 导包 import numpy as np numpy数组创建 创建全0数组,正态分布、随机数组等就不说了,提供了相应的方法通过已有数据创建有两种 arr1np.array([1,2,3,4,5]) 或者datanp.loadt…

vxe-grid\table 自定义动态列排序设置

实现动态加载的表格数据,根据设置动态控制指定的某些字段排序功能;如下图所示; 代码实现:标签内添加属性; :sort-config"{trigger:cell, defaultSort: {field: , order: desc}, orders:[desc, asc]}" sort-…

LinuxC编程——线程

目录 一、概念二、进程与线程的区别⭐⭐⭐三、线程资源四、函数接口4.1 线程创建4.2 线程退出4.3 线程回收4.3.1 阻塞回收4.3.2 非阻塞回收 4.4 pthread_create之传参4.5 练习 一、概念 是一个轻量级的进程,为了提高系统的性能引入线程。 进程与线程都参与cpu的统一…

这些可以将音频翻译成文字的工具你值得拥有

你是否曾经遇到过这样的情景:你收到了一段包含外国人发言内容的会议音频,但是由于自己的外语水平一般而却无法理解其中的外语内容?别担心,现在有一些神奇的翻译音频文件的软件可以帮助你解决这个问题!如果你还不知道翻…

电脑必备的3款简单好用小工具,建议收藏使用!

​在当今社会,电脑已成为我们工作、学习和娱乐的重要工具。除了拥有一台电脑,一些小工具的加入可以大大提升我们的效率和使用体验。 整理了 3 款比较实用的软件,个人觉得非常实用。,它们将让你的电脑使用更加便捷、高效。不管你是…

使用Prisma访问数据库

首先,确保你已经安装了 Prisma CLI。你可以使用以下命令进行安装: npm install prisma --save-dev接下来,你需要初始化 Prisma 项目,最后一个参数需要指定数据库类型,如postgresql,sqlist,mysql…

深入浅出对话系统——检索式对话系统进阶方法

引言 本文介绍检索式对话系统进阶方法,主要介绍两篇论文工作。 Fine-grained Post-training for Improving Retrieval-based Dialogue Systems 这里的post-training是定义在pre-training和fine-turning中间的阶段,具体的思想是用一些特定领域的数据去…

ControlNet

2023.8.10 Adding Conditional Control to Text-to-Image Diffusion Models 对于 T2I 扩散模型添加 条件控制 相关联比较大的几篇论文: 0.Abstract 可以为预训练的扩散模型提供额外的输入条件控制。不需要很多计算资源。 即使在小数据集上,也具有鲁棒…

中间人攻击与 RADIUS 身份验证

在数字时代,中间人(MitM)攻击已成为一种日益严重的威胁。根据网络安全风险投资公司的网络安全统计数据,预计到2025年,网络犯罪每年将给世界造成10.5万亿美元的损失,比2015年的3万亿美元大幅增加。这种令人震…

企业微信消息模板通过中转页面(h5)判断跳转pc还是跳小程序

需求:甲方要根据不同的端跳转不同端的详情页面,为什么要这样,是应为每次在PC端点击消息,都要扫码登录进入小程序,不想进入小程序,要打开PC端 1、在pc端的微信中点击消息,则打开PC后台管理系统 …

Telegram营销,全球跨境电商都在研究的营销策略

Telegram 目前有7 亿月活跃用户。作为一个如此流行和广泛的即时通讯平台, Telegram 已成为企业和客户沟通的重要即时通讯工具。 为了使企业能够快速有效地覆盖目标受众,Telegram 不断改进平台,提供一系列功能,例如可定制的自动化…

内网穿透实战应用-——【如何在树莓派上安装cpolar内网穿透】

如何在树莓派上安装cpolar内网穿透 文章目录 如何在树莓派上安装cpolar内网穿透前言1.在树莓派上安装cpolar2.查询cpolar版本号3.激活本地cpolar客户端4.cpolar记入配置文件 前言 树莓派作为一个超小型的电脑系统,虽然因其自身性能所限,无法如台式机或笔…

Vue Baidu Map--自定义点图标bm-marker

自定义点图标 将准备好的图标放到项目中 使用import引入&#xff0c; 并在data中进行声明 <script> import mapIconRed from ./vue-baidu-map/img/marker_red_sprite.png export default {data() {return {mapIconRed,}}, } </script>在<bm-marker>中加入参…

【C++】map和set

目录 一、容器补充1.序列式容器与关联式容器2.键值对3.树形结构的关联式容器 二、set1.set的介绍2.set的使用3.multset的介绍4.multset的使用 三、map1.map的介绍2.map的使用3.multimap的介绍4.multimap的使用 一、容器补充 1.序列式容器与关联式容器 我们已经接触过STL中的部…

FISCO BCOS V3.0 Air建链体验——对比V2.9建链差别

前提 好久不见&#xff0c;最近因为毕业的手续等问题&#xff0c;一直都没有更新&#xff0c;FISCO BCOS第二季task挑战赛如期展开啦&#xff0c;因为毕业的问题&#xff0c;也是非常遗憾的错过了上一期的task挑战赛&#xff0c;这一期一定双倍挑战&#xff0c;hhhhhh Air版本…

spring源码之--启动入口

前面的文章搭建过spring源码&#xff0c;这里暂时不做展开讲解 spring源码搭建-略 1、那么spring的源码入口从哪查看呢&#xff1f;springboot的源码是如何启动spring的源码呢&#xff1f;追着这个疑问总结了一下如下&#xff1a; 在spring源码中直接添加一个模块&#xff0c…

Jay17 2023.8.10日报

笔记 【python反序列化】 序列化 类对象->字节流&#xff08;字符串&#xff09; 反序列化 字节流->对象 python反序列化没PHP这么灵活&#xff0c;没这么多魔术方法。 import pickle import os class ctfshow(): def init(self): self.username0 self.password0 d…

uniapp-----封装接口

系列文章目录 uniapp-----封装接口 uniapp-----分包 文章目录 系列文章目录 uniapp-----封装接口 uniapp-----分包 文章目录 前言 一、技术 二、封装步骤 1.准备 ​编辑 2.代码填充 request.js&#xff1a; api.js&#xff1a; min.js 页面使用 总结 前言 uni…

数据库优化脚本执行报错

目录 一、执行数据库优化脚本 报错... 3 解决方法&#xff1a;... 4 1、直接注释掉RECYCLE_POOLS 赋值sql语句块... 4 2、手动修改脚本... 5 附录... 6 一、执行数据库优化脚本 报错 AutoParaAdj3.5_dm8.sql 1&#xff09;manager中报错 -20001: 执行失败, -7065 数据未…