收藏!用 Python 写一个抢票软件
本文介绍的是如何用 Python 语言实现 12306 自动预定列车票,也就是坊间常说的“抢票”,但个人觉得,这不算是“抢”,只不过是一定程度的自动化。
总体设计
所谓抢票软件,本质上就是基于浏览器驱动,实现登录、预定、确认信息的自动化。购买列车票涉及4个网页,相应的基本流程如下:
登录:输入用户名、密码,识别验证码,点击“登录”;
基本信息填写:出发地,目的地,出发日期,车票类型(普通或学生),车次类型选择,点击“查询”,如果目标车次尚有余票则点击“预定”,否则再次点击查询……;
订单信息填写:乘车人选择,席别选择,票种选择,点击“提交订单”;
订单确认:选择座位位置,点击“确认”。
详细设计
总体设计理清了抢票的主要步骤,进一步需要明确每个步骤中需要注意的问题。
1. 登录
登录过程中,自动输入用户名和密码比较简单,难点在于识别验证码。截至目前,各种自动识别验证码的方案准确率都不高,因此,本文采用“人工辅助”识别验证码,即:识别验证码由人工完成,选择图形验证码后点击“登录”。
2. 基本信息填写、查询、预定
整体上没有难点,但需要注意,出发地和目的地可能有多个车次,每个车次有多种席别,乘车方案可能比较复杂,比如:路途较远的情况下,对于 G 字头、D字头列车,二等座及以上可接受;对于 K 字头、T 字头列车,硬卧及以上可接受……。如此,在抢票的时候,需要按优先级轮询各种方案。以杭州 -> 成都为例,有 5 个车次可选,如下所示:
3. 订单信息填写
乘车人列表中可能有多个人的信息(如果你曾经帮别人买过车票的话,注册信息会保留),需要选择正确的乘车人、票种和席别,如下例子所示:
4. 订单确认
这一步很简单,点击“确认”即可,毕竟春运期间抢票,一般不会在意位置,能抢到已是幸运。
准备工作
根据总体设计,可以将抢票程序规划为 5 个主要函数:
__init__()
:初始化login_proc()
:登录模块filling_proc()
:基本信息填写模块booking_proc()
:查询、预订、订单信息填写模块confirm_proc()
:订单确认模块
1. 浏览器驱动
本文介绍的抢票软件基于 Chrome 浏览器,因此,需要下载与之版本匹配的驱动 chromedriver(附:下载网址)。注意与自己的 Chrome 版本对应,步骤如下:
首先,查看 Chrome 的版本,选择“设置” -> “关于 Chrome”,如下图版本为 66.x。
然后,进入 chromedriver 下载网址,根据 notes.txt 文件提供的信息选择正确版本的驱动。如下图,chromedriver2.38 支持 Chrome 版本为65-67:
2. Selenium 模块准备
Selenium 是一个用于 Web 应用程序自动化测试的工具,可直接运行在浏览器中,模拟真实用户操作。支持的浏览器包括 IE、Mozilla Firefox、Safari、Chrome、Opera 等。由于其功能强大,被广泛应用于网络爬虫的开发,本文将用它作为抢票程序的核心模块(附:下载及安装方法)。
3. 必要信息准备
列车购票官网经过数次改革,出发地、目的地、车次、席别等都不是明文,而是以编码表示,因此,需要提前准备好这些信息。信息获取方法:谷歌浏览器打开 12306 官网购票页面,鼠标右键“查看”可以获取到上述信息,以杭州 -> 成都为例:
#自定义变量区value_fromstation = '%u676D%u5DDE%2CHZH' # 始发站(杭州)value_tostation = '%u6210%u90FD%2CCDW' # 终点站(成都)value_date = '2018-05-10' # 出发时间username=u"username" # 用户名password="password" # 密码#杭州-成都:车次&席别&预定#车次信息字典,数据分别表示车次、一等座ID、二等座ID、无座ID、对应车次的预定按钮IDtrain_info = {"D2222":[['ZY_56000D222251', 'ZE_56000D222251', 'WZ_56000D222251'], 'ticket_56000D222251'],"D2262":[['ZY_56000D226251', 'ZE_56000D226251', 'WZ_56000D226251'], 'ticket_56000D226251']}
车次、票种编码,主要网页 URL 是固定的,如下:
#车票类型字典,"学生票"和"普通票"对应的IDticket_type_dict = {'student': '//input[@name="sf" and @id="sf1"]','common': '//input[@name="sf" and @id="sf2"]'}#车次类型字典train_type_dict = {'T': '//input[@name="cc_type" and @value="T"]', # 特快'G': '//input[@name="cc_type" and @value="G"]', # 高铁'D': '//input[@name="cc_type" and @value="D"]', # 动车'Z': '//input[@name="cc_type" and @value="Z"]'} # 直达#登陆页面urllogin_url = 'https://kyfw.12306.cn/otn/login/init'#个人信息页面urlinitmy_url = "https://kyfw.12306.cn/otn/index/initMy12306" #订票页面urlbook_url = 'https://kyfw.12306.cn/otn/leftTicket/init' #乘客选择页面urlconfirm_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
登陆模块 login_proc() 设计
请参见下面代码:
def __init__(self):"""Info:构造函数,创建一个浏览器对象"""print(u"欢迎使用列车订票工具")self.driver = webdriver.Chrome(self.driver_path)self.driver.implicitly_wait(300)def login_proc(self):"""Info:登陆过程处理函数,其中图形验证码需要手动选择"""self.driver.get(self.login_url)# sign in the user nametry:self.driver.find_element_by_id("username").send_keys(self.username)self.driver.find_element_by_id("password").send_keys(self.password)except Exception as err:print(u"输入用户名或密码失败!",err)#点击验证码,人工辅助,目前识别图形验证码比较困难,因此选择人工辅助 print(u"请自行选择验证码,点击登陆")while True:if(self.driver.current_url != self.initmy_url):time.sleep(1)else:print('Login finished!')break
基本信息填写模块 filling_proc() 设计
请参见下面代码:
def filling_proc(self,train_type,ticket_type):"""Info:填写起始站,终点站,出发时间,车次类型,车票类型等信息"""print (u'列车类型:', train_type)print (u'车票类型:', ticket_type)# 打开订票网页self.driver.get(self.book_url)# 选择始发站self.driver.add_cookie({"name": "_jc_save_fromStation", "value": self.value_fromstation})# 选择终点站self.driver.add_cookie({"name": "_jc_save_toStation", "value": self.value_tostation})# 选择出发日期self.driver.add_cookie({"name": "_jc_save_fromDate", "value": self.value_date})self.driver.refresh()# 选择车次类型 if (train_type == 'T' or train_type == 'G' or train_type == 'D' or train_type == 'Z'):self.driver.find_element_by_xpath(self.train_type_dict[train_type]).click()else:print (u"车次类型异常或未选择!(train_type=%s)" % train_type)# 选择车票类型if (ticket_type == 'student' or ticket_type == 'common'):self.driver.find_element_by_xpath(self.ticket_type_dict[ticket_type]).click()else:print (u"车票类型异常或未选择!(train_type=%s)" % ticket_type)
查询、预订、订单信息填写模块 booking_proc() 设计
请参见下面代码:
def booking_proc(self,refresh_interval=0):"""Info:订票处理过程,循环查询符合条件的车次,如果存在则点击“预定”"""book_ticket_flag = False# 循环查询while True:time.sleep(refresh_interval)# 点击“查询”按钮,刷新页面开始查询,查询按钮的ID="query_ticket"search_btn = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="query_ticket"]')))search_btn.click()# 扫描查询结果,根据自定义车次字典train_info提供的信息,逐一查询try:for train in self.train_info:print(u"当前查询车次为:"+train)# 根据车次查询对应的席别:商务,一等,二等,无座等seat_list= self.train_info.get(train)for seat in seat_list[0]:ticket_seat_id = '//*[@id="' + seat + '"]'# 席别IDtic_tb_item = 'default'# 获取车票数量信息:"-","无","数字"tic_tb_item = WebDriverWait(self.driver, 2).until(EC.presence_of_element_located((By.XPATH, ticket_seat_id)))tic_ava_num = tic_tb_item.text# 无票或未开售,则结束当前查询if(tic_ava_num == u'无' or tic_ava_num == u'*'): continue# 如果车次有票,则点击对应车次的“预定”按钮else:book_ticket_btn = '//*[@id="' + seat_list[1] + '"]/td[13]/a'self.driver.find_element_by_xpath(book_ticket_btn).click()book_ticket_flag = Trueprint(u"开始预定")breakif (book_ticket_flag):breakexcept Exception as err: print(err)# 网络状态不好的时候,点击查询按钮,可能返回查询结果失败,对此异常可再次点击search_btn.click()if (book_ticket_flag):break
订单确认模块 confirm_proc() 设计
请参见下面代码:
def confirm_proc(self):"""Info:点击“预定”之后,需要确认乘客信息和座位信息"""# 判断页面跳是否转至乘客选择页面 while True:if (self.driver.current_url == self.confirm_url):print (u'页面跳转成功!')breakelse:print (u'等待页面跳转...')time.sleep(1)# 乘车人选择:针对乘车人列表多于一人的情况print(u"选择乘客")while True:try:# 选择乘车人列表中的第二个人self.driver.find_element_by_xpath('//*[@id="normalPassenger_1"]').click()breakexcept Exception as err:print (u'等待常用联系人列表。。。',err) time.sleep(0.5)try:print(u"提交订票信息")self.driver.find_element_by_xpath('//*[@id="submitOrder_id"]').click()time.sleep(1.5)print(u"确认订票信息")self.driver.find_element_by_xpath('//*[@id="qr_submit_id"]').click() except Exception as err:print (err)
如需查看完整代码和详细讲解,欢迎订阅专栏。
你的收获
掌握学习编程语言的方法。与市面上那些力求面面俱到、动辄数百页的辅导书不同,本专栏将编程语言的学习路线提炼为基础、中级、高级三层,并依此循序渐进,此路线亦可用于学习其它编程语言。
掌握 Python 编程语言核心概念,包括数据结构、语句、函数、类等。丰富实例助力读者编程实践,快速入门 Python。
掌握高级知识点,包括模块、标准库、文件、流、数据库、网络编程、图形界面等,并具备基于这些知识点编写小应用的能力。
专栏设计
零基础学习,循序渐进
内容全面,提炼要义
理论结合实践,提升学习效率
本专栏的目标是带领读者快速掌握 Python 要义,进而上手实践。专栏分为四个部分:基础篇、中级篇、高级篇以及扩展篇,对于初学者,建议按照顺序阅读。
第一部分:基础篇。从 Python 的起源、现状和前景讲起,首先带领读者搭建开发环境,随后介绍 Python 的基础知识和基本概念,包括列表、元组、字符串、字典以及各种语句,以简练而生动的文字引导读者步入 Python 的世界。
第二部分:中级篇。循序渐进地介绍一些对初学者来说相对难以理解的内容,包括函数、类、继承、函数重写、作用域、参数传递、错误及异常等内容。
第三部分:高级篇。这部分立足于实践,并将介绍一些相对高级的主题,包括模块、标准库、文件、流、数据库、网络编程、图形界面等。通过学习这部分内容,读者将掌握模块的原理和利用标准库将 Python 与数据库、网络、图形界面等工具结合使用。
第四部分:扩展篇。结合实际应用场景,带领读者完成两个小程序的设计和实现。
Python 已被多家平台评选为 2020 年最值得掌握的编程语言第一名!相信精通这门语音,一定会让你在未来获得更大的发展空间!
即日起至 2 月 23 日, 《Python 开发 14 天快速入门》限时特惠!现在订阅本专栏,即可开启 Python 学习之路,还能进群和作者一起交流学习哦~
收藏!用 Python 写一个抢票软件相关推荐
- 第13课:实战之用 Python 写一个抢票软件
本文将介绍如何用 Python 语言实现 12306 自动预定列车票,也就是坊间常说的"抢票",但个人觉得,这不算是"抢",只不过是一定程度的自动化. 总体设计 ...
- 用python写一个抢票脚本
写一个抢票脚本需要了解一些网络爬虫的知识,以及如何使用 Python 进行网络请求. 首先,你需要找到票务网站的 API,并了解其请求方式.请求参数等信息.然后,你可以使用 Python 的第三方库如 ...
- python抢票软件代码_Python 写一个抢票软件
总体设计 所谓抢票软件,本质上就是基于浏览器驱动,实现登录.预定.确认信息的自动化.购买列车票涉及4个网页,相应的基本流程如下: 登录:输入用户名.密码,识别验证码,点击"登录": ...
- python软件界面-用Python写一个语音播放软件
原标题:用Python写一个语音播放软件 单位经常使用广播进行临时事项的通知(将文字转换为语音然后通过功放广播),但是市面上多数语音播放软件都是收费的,要么发音失真,要么不够稳定--经常出现莫名其妙的 ...
- python编写一个软件-python写一个随机点名软件的实例
最近有个随机点名软件的需求,故写了一个,上代码:github地址 # -*- coding: utf-8 -*- # @Time : 18-12-31 下午4:21 # @Author : Felix ...
- python写软件实例-python写一个随机点名软件的实例
最近有个随机点名软件的需求,故写了一个,上代码:github地址 # -*- coding: utf-8 -*- # @Time : 18-12-31 下午4:21 # @Author : Felix ...
- 给我编写一个抢票软件
在编写抢票软件之前,你需要先了解抢票的基本原理.抢票软件是通过自动化地发送大量的 HTTP 请求到服务器,试图在票务系统中抢到购票资格. 在编写抢票软件时,你需要考虑以下几个方面: 如何发送 HTTP ...
- python语音播报-用Python写一个语音播放软件
单位经常使用广播进行临时事项的通知(将文字转换为语音然后通过功放广播),但是市面上多数语音播放软件都是收费的,要么发音失真,要么不够稳定--经常出现莫名其妙的故障,容易给工作带来被动.学Python这 ...
- python读音播报-用Python写一个语音播放软件
单位经常使用广播进行临时事项的通知(将文字转换为语音然后通过功放广播),但是市面上多数语音播放软件都是收费的,要么发音失真,要么不够稳定--经常出现莫名其妙的故障,容易给工作带来被动.学Python这 ...
最新文章
- 禅道Docker安装包发布
- python可以做什么工作好-Python可以做什么工作?Python有哪些方向?
- 计算机中的信息表示 ppt模板,计算机中信息的表示.ppt
- 关于python3中的包operator(支持函数式编程的包)
- 安全,从写第一行代码开始!
- 三次多项式曲线php,多项式计算的效率测试,多项式计算效率_PHP教程
- html5 字母单词拖拽,HTML5拖拽
- ArcGIS制图(一)之流向图
- rtmp中flv和flv文件的区别
- maya导入abc动画_如此导出ABC缓存,扩展秘籍(二)!!!
- splunk 日志分析软件 简介
- BAT的校园大赛,都秀出了哪些肌肉?
- c语言ans作用,ANS标准定义C语言是什么?
- 星期五五–大数据,Doppio和假Linus Torvalds
- 如何制作优秀的数据可视化报告(学习篇)
- 天翼云打造国云安全品牌 铸牢企业云上安全防线
- Nginx源码安装及调优配置(二)
- React基础(叁)———事件处理
- w7计算机u盘在哪里,win7电脑无法发现u盘怎么解决
- MCU基础以及RTOS原理知识分享