不知不觉,一年一度的春运抢票大幕已经拉开,想快速抢到回家的车票吗?作为程序员,这些技术手段,你一定要知道。
为了让大家更快捷更便利的抢火车票,各种各样的抢票软件应需而生,这类软件大部分都是付费抢票的机制。
作为程序员,如何用技术手段抢到回家的票?来看看用 Python 写的抢票脚本。
windows 8.1
python3.6.1
firefox插件 geckodriver.exe
引入要的模块
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
from
selenium.webdriver.support.select import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
登陆模块
首先需要选择使用的浏览器,此处以 firefox 为例,下载:geckodriver.exe 。
下载地址:
https://github.com/mozilla/geckodriver/releases
提到的 stations.txt 可以直接看这个:
车站信息:
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9042
将 geckodriver.exe 放到 python.exe 同级目录下即可(如果有报错的情况下,放一个该文件到与 firefox.exe 同级目录下,并添加环境变量)
#可以用input,也可以直接放入到后面的用户名、密码输入框中
#可以利用标准输入进行批量的操作,此处以个人抢票操作为例
# username = str(input('请输入你的用户名:'))
# password = str(input('请输入你的密码:')) #这两行可以暂时忽略
browser = webdriver.Firefox() #驱动firefox浏览器
browser.get("https://kyfw.12306.cn/otn/login/init") #启动浏览器后进入该链接下
browser.find_element_by_id('username').clear()
browser.find_element_by_id('username').send_keys(‘xxxxx’) #xxxxx更换为用户名
browser.find_element_by_id('password').send_keys(‘xxxxx’) #xxxxx更换为密码
time.sleep(10) #此时验证码自行点击,该处设置10秒延迟,可以自己设置
try:
browser.find_element_by_id('loginSub'
).click() #点击登陆操作,该id为登陆按钮
#或者 browser.find_element_by_link_text('登陆').click() #标签显示的名称
except:
browser.find_element_by_class_name('touclick-bgimg touclick-reload touclick-reload-normal').click() #try中验证码输入点错了会在此处刷新一次
time.sleep(20) #第二次输入验证码前等待20秒,可以自己设置,第一次输入无误直接跳过
browser.find_element_by_id('loginSub').click() #重新输入验证码后的点击登陆
跳转模块
time.sleep(2)
clickReserve = browser.find_element_by_link_text('车票预订').click()
time.sleep(2)
jsf = 'var a = document.getElementById("fromStation");a.value = "BJP"'
browser.execute_script(jsf)
jst = 'var a = document.getElementById("toStation");a.value = "LZJ"'
browser.execute_script(jst)
js = "document.getElementById('train_date').removeAttribute('readonly')"
browser.execute_script(js)
browser.find_element_by_id('train_date').clear()
browser.find_element_by_id('train_date').send_keys('2018-02-01')
search = browser.find_element_by_id('query_ticket').click()
开始购票
此处,就是点击预定的操作,我在这里只是举一个方法例子,也可以通过不断点击直到成功(这样可以避免网站倒计时和实际时间的时间差影响,但是不知道 12306 在抢票时对不断快速访问有没有限制)。
start_time = "Thu Jan 04 08:00:00 2018"
b = time.mktime(time.strptime(start_time,"%a %b %d %H:%M:%S %Y")) print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime(b)) )
a = float(b)-time.time()
time.sleep(a)
try:
WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "ticket_2400000Z550L")))
ticket = browser.find_element_by_xpath('//tr[@id="ticket_2400000Z550L"]/td[13]/a').click() except:
browser.find_element_by_id('query_ticket').click()
WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID, "ticket_2400000Z550L")))
ticket = browser.find_element_by_xpath('//tr[@id="ticket_2400000Z550L"]/td[13]/a').click()
"""
normalPassenger_8 数字表示该账号下的第几位,默认从0开始如果是第一个则为normalPassenger_0
"""WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "normalPassenger_8")))
browser.find_element_by_id('normalPassenger_8').click() s = Select(browser.find_element_by_id('seatType_1'))
s.select_by_value('6') browser.find_element_by_id('submitOrder_id').click()
WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "qr_submit_id")))
browser.find_element_by_link_text('提交订单')
browser.find_element_by_id('qr_submit_id').click()
需要替换的地方:
用户名,密码。
起始地点和目的地的 value 值,查 stations.txt 修改即可。
出发时间。
自己选择车次的 xpath 路径,路径不用变,变对应 id 即可。
勾选用户的位置(如果只要一个用户,默认用:normalPassenger_0)。
所选座位类别,默认为有票的类别里最便宜的种类。
其余的在测试中都相同,没有发现有变化,在使用前,可以测试一下代码,测试是注意注释掉提交订单的代码(下单有取消限制,每天好像只能取消三次),测试时网速正常。
有人说用浏览器执行速度会慢,确实对于可以直接识别验证码的脚本而言,没有界面的会更快一些,但是实际上所用时间为预定开始到结束,相同网络下,代码执行时间是要快于人工操作的,
另外,时间可以研究一下,之前研究过某宝的时间,秒杀时间是要比北京时间提前一点几秒的,感觉全国各地有微小时间差的。
"""
说明:
1.该脚本主要是提供一个实现思路,实现方法有很多,可以优化的地方也有很多,触发机制也可以自己设置,代码以压缩到最短,只是为了让大家都可以看明白
2.正常网络状况下,不设置指定时间时,从点击确认验证码到下单基本上1秒左右,所以速度上还是没问题的
3.由于同时勾选多人和单人使用所需时间基本相同,希望该方法只用于技术交流,请勿作为黄牛使用
4.在作为技术交流的情况下,如果验证码可以实现将可以完全实现自动抢票:
--1>验证码有一定规律和数量,可以利用脚本获取所有图片,并加上相应标签
--2>将页面的文字和标签相匹配,再将图片进行相似度计算,对对应图片进行点击操作
--3>或是训练深度学习的图片识别模型,通过算法识别
"""from selenium import webdriverfrom selenium.webdriver.common.keys import Keysimport timefrom selenium.webdriver.support.select import Selectfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Firefox()
browser.get("https://kyfw.12306.cn/otn/login/init")
browser.find_element_by_id('username').clear()
browser.find_element_by_id('username').send_keys('xxxxxxx')
browser.find_element_by_id('password').send_keys('xxxxxxx')
time.sleep(10)try
:
browser.find_element_by_id('loginSub').click()except:
browser.find_element_by_class_name('touclick-bgimg touclick-reload touclick-reload-normal').click()
time.sleep(15)
browser.find_element_by_id('loginSub').click()time.sleep(2)
clickReserve = browser.find_element_by_link_text('车票预订').click()WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "fromStation")))
jsf = 'var a = document.getElementById("fromStation");a.value = "BJP"'browser.execute_script(jsf)
jst = 'var a = document.getElementById("toStation");a.value = "LZJ"'browser.execute_script(jst)
js = "document.getElementById('train_date').removeAttribute('readonly')"browser.execute_script(js)
browser.find_element_by_id('train_date').clear()
browser.find_element_by_id('train_date').send_keys('2018-02-02')
search = browser.find_element_by_id('query_ticket').click()start_time = "Thu Jan 04 10:00:00 2018" b = time.mktime(time.strptime(start_time,"%a %b %d %H:%M:%S %Y"))
print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime(b)) ) a = float(b)-time.time() time.sleep(a) browser.find_element_by_id('query_ticket').click() try:
WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "ticket_2400000Z550L")))
ticket = browser.find_element_by_xpath('//tr[@id="ticket_2400000Z550L"]/td[13]/a').click()except:
browser.find_element_by_id('query_ticket').click()
WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID, "ticket_250000K8880L")))
ticket = browser.find_element_by_xpath('//tr[@id="ticket_250000K8880L"]/td[13]/a').click()"""
normalPassenger_8 数字表示该账号下的第几位,默认从0开始如果是第一个则为normalPassenger_0
"""WebDriverWait(browser,10
).until(EC.presence_of_element_located((By.ID, "normalPassenger_8")))
browser.find_element_by_id('normalPassenger_8').click()
s = Select(browser.find_element_by_id('seatType_1'))
s.select_by_value('6')
browser.find_element_by_id('submitOrder_id').click()
WebDriverWait(browser,10).until(EC.presence_of_element_located((By.ID, "qr_submit_id")))
browser.find_element_by_link_text('提交订单')
作者:LGC247CG
简介:大学时候就已经接触 Python,并研究 Python 爬虫,数据分析,文本处理,图像处理等,有五年应用经验,工作以后主要用在 Linux 系统运维脚本。
编辑:陶家龙、孙淑娟
投稿:有投稿、寻求报道意向技术人请联络 editor@51cto.com
一波三折,APM监控系统对于OSGI架构的探索实践
饿了么异地双活数据库实战
我用Python玩小游戏“跳一跳”,瞬间称霸了朋友圈!