当我准备出门时,发现了......我可以用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 flagdef isElementExist(driver):flag=Trueele = driver.find_elements(by=By.CLASS_NAME, value='btn72')if len(ele) == 0:flag = Falsereturn flagif len(ele) == 1:return flagelse:flag = Falsereturn flagdef 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分钟内支付!")returnif __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.rhkb.cn/news/84056.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

列队 Queue 接口概述

在Java中,Queue(队列)是一种基本的数据结构,用于按照先进先出(FIFO)的顺序存储元素。Java提供了多种实现Queue接口的类,以下是几种常见的实现方式: LinkedList:LinkedLis…

RISC-V公测平台发布 · 使用YCSB测试SG2042上的MySQL性能

实验介绍: YCSB(全称为Yahoo! Cloud Serving Benchmark),该性能测试工具由Java语言编写(在之前的MC文章中也提到过这个,如果没看过的读者可以去看看之前MC那一期),主要用于云端或者…

【位操作符的几种题型】

位操作符的几种题型 目录 题型一:寻找“单身狗”。 题型二:计算一个数在二进制中1的个数 题型三:不允许创建临时变量,交换两个整数的内容 题型一:寻找“单身狗”。 1.1题目解析 在一个整型数组中,只有…

SUB-1G SOC芯片DP4306F 32 位 ARM Cortex-M0+内核替代CMT2380F32

DP4306F是一款高性能低功耗的单片集成收发机,集成MO核MCU,工作频率可覆盖200MHiz^ 1000MHz。 支持230/408/433/470/868/915频段。该芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK解调器等功能模块。通过SPI接口可以对输出功率、频道选…

element-plus的日期选择器限定选择范围

目录 前言一、最近30天总结 前言 提示:这里可以添加本文要记录的大概内容: element-plus的日期选择器限定选择范围,由于数据的获取范围限定,需要前端处理一下日期的选择范围 提示:以下是本篇文章正文内容&#xff0c…

软考高级之系统架构师之数据通信与计算机网络

概念 OSPF 在划分区域之后,OSPF网络中的非主干区域中的路由器对于到外部网络的路由,一定要通过ABR(区域边界路由器)来转发,既然如此,对于区域内的路由器来说,就没有必要知道通往外部网络的详细路由,只要由…

【计算机网络】概述及数据链路层

每一层只依赖于下一层所提供的服务,使得各层之间相互独立、灵活性好,已于实现和维护,并能促进标准化工作。 应用层:通过应用进程间的交互完成特定的网络应用,HTTP、FTP、DNS,应用层交互的数据单元被称为报…

音频光耦合器

音频光耦合器是一种能够将电信号转换为光信号并进行传输的设备。它通常由发光二极管(LED)和光敏电阻(光电二极管或光敏电阻器)组成。 在音频光耦合器中,音频信号经过放大和调节后,被转换为电流信号&#xf…

【密码学】六、公钥密码

公钥密码 1、概述1.1设计要求1.2单向函数和单向陷门函数 2、RSA公钥密码体制2.1加解密2.2安全性分析 3、ElGamal公钥密码体制3.1加解密算法3.2安全性分析 4、椭圆曲线4.1椭圆曲线上的运算4.2ECC 5、SM2公钥密码体制5.1参数选取5.2密钥派生函数5.3加解密过程5.3.1初始化5.3.2加密…

ThinkPHP6企业OA办公系统

有需要请加文章底部Q哦 可远程调试 ThinkPHP6企业OA办公系统 一 介绍 勾股OA基于ThinkPHP6开发,前端Layui,数据库mysql,是一款实用的企业办公系统。可多角色登录,集成了系统设置、人事管理、消息管理、审批管理、日常办公、客户…

pytest 用例运行方式

一、命令行方式运行 执行某个目录下所有的用例,符合规范的所有用例 进入到对应的目录,直接执行pytest; 例如需要执行testcases 下的所有用例; 可以进入testcases 目录; 然后执行pytest 进入对应目录的上级目录,执行pytest 目录名称/ ; ; 例如需要执行testcases 下…

【Android】在Windows11系统上运行VisualStudioEmulator forAndroid

这是一个x86架构处理器的安卓模拟器, 在Visual Studio开发工具上用的,也是运行在Hyper-V虚拟机上的,相比其它的模拟器的性能好,占用磁盘空间小,操作简洁方便,非常适合开发人员调试安卓手机模拟。 安装 首…

K8S系列文章之 Traefik快速入门

traefik 与 nginx 一样,是一款优秀的反向代理工具,或者叫 Edge Router。至于使用它的原因则基于以下几点 无须重启即可更新配置自动的服务发现与负载均衡与 docker 的完美集成,基于 container label 的配置漂亮的 dashboard 界面metrics 的支…

要实现智能制造到底有多难?先看看这一步...

是新朋友吗?记得先点上方蓝字关注Ruff 智能制造、数字化转型,已成为当下制造业最炙手可热的话题,政府工作报告中已多次提到,为了促进数字经济发展,加强数字中国建设整体布局,打造智能工厂、智慧工厂。愿景是…

论文阅读---《Unsupervised Transformer-Based Anomaly Detection in ECG Signals》

题目:基于Transformer的无监督心电图(ECG)信号异常检测 摘要 异常检测是数据处理中的一个基本问题,它涉及到医疗感知数据中的不同问题。技术的进步使得收集大规模和高度变异的时间序列数据变得更加容易,然而&#xff…

SEO搜索引擎优化

目录 场景 内部业务To B (Business-to-Business,B2B)需要降低SEO,反爬 客户业务To C (Business-to-Consumer,B2C)需要提高SEO TDK优化 Title(标题) Description(描述) Keywords&#xff…

matplotlib 笔记 plt.grid

用于添加网格线 主要参数 visible 布尔值,True表示画网格 which表示要显示的刻度线类型,可以是 major(主刻度)或 minor(次刻度),或者同时显示(both)alpha 透明度 …

Effective Java笔记(27)消除非受检的警告

用泛型编程时会遇到讲多编译器警告 : 非受检转换警告( unchecked cast warning )、非受检方法调用警告、非受检参数化可变参数类型警告( unchecked parameterized vararg type warning),以及非受检转换警告…

【Pyhthon实战】Python对全校电费查询采集并可视化分析

前言 今天,我来说说怎么抓取宿舍电费的过程。我们学校是在完美校园交电费的,我们可以不用取抓包完美校园的数据接口,我们可以直接登录学校的一卡通网站,每个学校都有,大家可以自己找找,这里我为什么要抓包呢,因为学校提供的网站已经打不开了,这里就不介绍怎么抓包了。 …

9篇论文速览 ICML 2023 测试时自适应(TTA)最新研究进展

测试时自适应对于领域转移下真实机器感知应用的成功至关重要,近年来,研究者们仍然在不断优化现有的方法。在今年的ICML中,TTA相关的研究也有了最新进展。 1.Uncovering Adversarial Risks of Test-Time Adaptation 标题:揭示测试…