要过年了,12306监控抢购车票软件已经写好了,亏我Python学得好
Posted Python可乐的呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了要过年了,12306监控抢购车票软件已经写好了,亏我Python学得好相关的知识,希望对你有一定的参考价值。
目录
一、效果展示
二、代码详解
1 导入库
2 确定好购票基本信息
3 登录12306
4 模拟滑动滑块
5 处理疫情特殊要求
6 点击购票并填写出发地、目的地、出发时间
7 锁定车票
三、实现监控购买
注意
环境
代码
大家有没有这种感觉,一到国庆、春节这种长假,抢火车票就非常困难?各大互联网公司都推出抢票服务,只要加钱给服务费就可以增加抢到票的几率。有些火车票代售网点和一些加速买票软件,说你只要给100元服务费就可以优先帮忙抢到票。
本文和你一起探索抢票软件背后的原理。
很多人学习蟒蛇,不知道从何学起。 很多人学习寻找python,掌握了基本语法之后,不知道在哪里案例上手。 很多已经可能知道案例的人,却不怎么去学习更多高深的知识。 这三类人,我给大家提供一个好的学习平台,免费获取视频教程,电子书,以及课程的源代码! QQ群:101677771 欢迎加入,一起讨论学习
一、效果展示
在正式进入代码讲解之前,先来看下本文的实现效果。
如果不是为了演示效果,直接在最后确定阶段加一个延时点击确定,应该不到45秒可以锁定一张票,只要在30分钟之内付款即可。
二、代码详解
本小节会详细解锁抢票软件是如何模拟登录网站,进行自动买票的。为了更清晰地给大家展示,部分代码没有写成函数,直接裸代码运行,让需要买票的朋友可以自己应用软件进行购票。
1 导入库
首先导入本文需要加载的库,如果你有些库还没有安装,导致运行代码时报错,可以在Anaconda Prompt中用pip方法安装。
import json
import time
from captcha import *
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import wait
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
#导入库
2 确定好购票基本信息
导入库后,在python代码中填写你购票的基本信息。
purpose = \'ADULT\' #购买成人票,如果是学生票,需调整代码
names = [\'谢朝阳\'] #填写购票人姓名
date = \'2021-09-21\' #填写购票日期
start_station = \'深圳\' #购票出发站
end_station = \'长沙南\' #购票目的站
password = \'11234567xyz\' #登录12306的秘密
username =\'xiezhaoyang122700\' #登录12306的账号
trains = [\'G1004\', \'G80\', \'G6028\', \'G6182\', \'G6016\'] #你想买的班次
#填写基本信息
本文预订的是2021年9月21日从深圳到长沙南的高铁票,你可以根据自己的实际需要进行调整。由于有些班次的时间过早或过晚,买了也很不方便,所以可以在trains中挑选出你满意的班次进行购票。在这里需要提醒大家,我之前在尝试代码时碰到的坑,那就是时间中如果有个位数要在前面填0。比如2021年9月2日,你在填写购票日期date时要写成\'2021-09-02\',否则在运行代码时日期总是填不进去。
3 登录12306
确定好购票的基本信息后,就可以应用python模拟登录12306了,代码如下:
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
browser = webdriver.Chrome(options=options)
browser.maximize_window()
login_url = \'https://kyfw.12306.cn/otn/resources/login.html\'
#ticket_url = \'https://kyfw.12306.cn/otn/leftTicket/init\'
browser.get(login_url)
time.sleep(0.5)
wait.WebDriverWait(browser, 5).until(EC.element_to_be_clickable((By.CLASS_NAME,\'login-hd-account\'))).click()
input_name = browser.find_element_by_id(\'J-userName\')
input_pd = browser.find_element_by_id(\'J-password\')
input_name.send_keys(username)
input_pd.send_keys(password)
login = browser.find_element_by_id(\'J-login\')
login.click()
#登录12306
整体思路是:
1.应用python模拟调用google浏览器;
2.输入12306网址;
3.等网页加载完全后点击账户密码登录;
4.找到账号密码的id,把账户密码信息填充进去;
5.找到登录id,模拟点击登录按钮。
在这一小节中要注意两个点。
一、要在python安装目录中放和google版本匹配的chromedriver,供python调用。
二、要学会填写账户密码信息的id。
首先,在google浏览器中输入12306登录网址:
中国铁路12306
接着点击账户密码登录,会出现如下界面:
然后点击红框中的三个点,找到更多工具,点击开发者工具,会出现如下界面:
点击红框中的箭头,把鼠标移动到账户框上去,就会出现如下界面:
右边变灰的框里就会出现对应的id,点击账号框,再把鼠标移动到右边变灰的字符上去,点击右键,会出现copy element的选项,复制下来即可。
<input type="text" class="input" id="J-userName" placeholder="用户名/邮箱/手机号" style="height: 44px; line-height: 44px; outline: black 0px;" aria-label="请输入用户名/邮箱/手机号" title="请输入用户名/邮箱/手机号">
发现了吗?源代码input_name中要填写的
browser.find_element_by_id(\'J-userName\')内容,即为id="J-userName"中的信息。
4 模拟滑动滑块
输入完用户名和密码,点击立即登录后,会出现如下滑块验证要求。
运行如下代码即可拖动滑块进行验证。
browser.implicitly_wait(5)
print(\'=====开始处理滑动验证码=====\')
track = [300, 400, 500]
for i in track:
try:
btn = browser.find_element_by_xpath(\'//*[@id="nc_1__scale_text"]/span\')
ActionChains(browser).drag_and_drop_by_offset(btn,i,0).perform()
except:
time.sleep(2)
#拉动滑块验证
其中,browser.implicitly_wait(5)表示隐性等待5秒,track中放的是滑块拉动的距离。
5 处理疫情特殊要求
完成滑块验证要求后,会出现如下疫情特殊要求提示:
用如下代码点击确认即可。
browser.implicitly_wait(5)
browser.find_element_by_xpath(\'/html/body/div[5]/div[2]/div[3]/a\').click()
time.sleep(2)
#疫情特殊要求
browser.find_element_by_xpath和id的区别是,在右键复制时要copy XPath或copy full XPath。
6 点击购票并填写出发地、目的地、出发时间
接下来是选择买票,并将出发地、目的地、出发时间等信息填写进去。
browser.find_element_by_xpath(\'//*[@id="J-chepiao"]/a\').click()
browser.find_element_by_xpath(\'//*[@id="megamenu-3"]/div[1]/ul/li[1]/a\').click()
browser.find_element_by_xpath(\'//*[@id="qd_closeDefaultWarningWindowDialog_id"]\').click()
#选择买票
def input_info():
print(\'=====开始买票=====\')
from_station = browser.find_element_by_xpath(\'//*[@id="fromStationText"]\')
from_station.send_keys(Keys.ENTER)
from_station.send_keys(Keys.CONTROL, \'a\')
from_station.send_keys(start_station, Keys.ENTER)
browser.implicitly_wait(5)
to_station = browser.find_element_by_xpath(\'//*[@id="toStationText"]\')
to_station.send_keys(Keys.ENTER)
to_station.send_keys(Keys.CONTROL, \'a\')
to_station.send_keys(end_station, Keys.ENTER)
browser.implicitly_wait(5)
start_date = browser.find_element_by_xpath(\'//*[@id="train_date"]\')
start_date.send_keys(Keys.ENTER)
start_date.send_keys(Keys.CONTROL, \'a\')
start_date.send_keys(Keys.CONTROL, \'x\')
start_date.send_keys(date, Keys.ENTER)
browser.implicitly_wait(5)
wait.WebDriverWait(browser, 3).until(EC.element_to_be_clickable((By.ID,\'query_ticket\'))).click()
input_info()
input_info()
#将出发地、目的地、出发日期填进去
得到的结果如下:
这里需要注意的是我调用了两遍input_info函数,因为12306可能采取了一些反爬措施,一遍输入进去后查不出东西,显示为灰色。
7 锁定车票
最后是依次查找trains中的车次是否有票,有的话点击购买锁定车票。
trList = browser.find_elements_by_xpath(".//tbody[@id=\'queryLeftTable\']/tr[not(@datatran)]")
for tr in trList:
trainNum = tr.find_element_by_class_name("number").text
if trainNum in trains:
leftTicket = tr.find_element_by_xpath(".//td[4]").text
print(\'leftTicket\', leftTicket)
if leftTicket == \'有\' or leftTicket.isdigit():
orderBtn = tr.find_element_by_class_name("btn72")
orderBtn.click()
browser.implicitly_wait(5)
passengerLabels = browser.find_elements_by_xpath(".//ul[@id=\'normal_passenger_id\']/li/label")
for passengerLabel in passengerLabels:
name = passengerLabel.text
if name in names:
passengerLabel.click()
browser.implicitly_wait(20)
# 获取提交按钮
submitBtn = browser.find_element_by_id("submitOrder_id")
submitBtn.click()
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
time.sleep(2)
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
break
#依次查找trains中的车次是否有票,有的话点击购买
所以,如果你有特别心仪的车次,可以在trains中放在最前面,依次填写觉得还行的车次。至此,应用python解锁抢票软件背后的原理已讲解完毕,感兴趣的朋友可以自己跟着本文实现一遍。
12306不定期会更新买票界面,所以过一段时间可能之前的代码就要进行一些调整,需要自己弄清里面的原理,才可以以不变应万变。本文的代码没有进行高级的封装,只为大家能更清楚地了解每一步,能在抢票高峰期买到自己心仪的票。
也写得很基础,没有进一步的调优缩短时效,感兴趣的朋友可以自行研究,如有任何疑问可以跟我沟通。
三、实现监控购买
原代码只能实现购票,我对代码进行了修改,增加了监测和抢票成功推送功能。
需要自行输入12306账号、密码,购买车次、时间、出发站、目的站、server酱key(Server酱·Turbo版 (ftqq.com)去申请)
经测试可成功购票,但有如下问题需要
注意
1.登录测试过多可能会导致滑块验证失败,可自行点击刷新,即可自动执行后续代码(懒得写刷新验证了,只要不是多次运行,一般不会有这个问题)
2.main()中,买票buy那一块,因为我是要抢票,等待时间设置为2,如果是监测,建议设置时间长一点,因为有可能被反爬
3.买票提交按钮可能会有bug,于是我在main中增加了一次选择来确保。但无论如何,进入提交页面你都会收到微信提示,为了保险,建议去看一下是否真的提交了,手动提交也不是不可以。
4.多人买票请在buy()函数下names里填入
5.代码中那么多**code,是我用来标记这段代码是否执行成功,如果没有成功就重复执行,如果code=0,代码没成功,再从头执行,gmcode和code感觉有点重复了,但是,管他呢,能运行就行了, 滑稽.jpg
6.我只是个业余程序猿,代码改的丑陋,我尽量写的通俗易懂了,大佬勿喷。
环境
(食用本代码需要一定的基础知识,新手估计挺难得)
- python3
- webdriver
以及一些库,我用pycharm,没有的库可以直接导入
还有,我觉得最主要的就是webdriver,自己有的话更好,配置的话可能需要很久时间,也挺麻烦的
代码
# -*- coding:utf-8 -*-
import json
import requests
import time
from captcha import *
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import wait
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
# 定义一系列code来确保每一步执行成功再进入下一步
global logincode, hkcode, yzcode, xpcode, cpcode, gmcode, code
# 初始化
def init_program():
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
browser = webdriver.Chrome(options=options)
browser.maximize_window()
return browser
# 登录12306
def login(browser):
global logincode
logincode = 0
password = \'\' # 登录12306的秘密
username = \'\' # 登录12306的账号
login_url = \'https://kyfw.12306.cn/otn/resources/login.html\'
# ticket_url = \'https://kyfw.12306.cn/otn/leftTicket/init\'
try:
browser.get(login_url)
time.sleep(0.5)
wait.WebDriverWait(browser, 5).until(EC.element_to_be_clickable((By.CLASS_NAME, \'login-hd-code\'))).click()
input_name = browser.find_element_by_id(\'J-userName\')
input_pd = browser.find_element_by_id(\'J-password\')
input_name.send_keys(username)
input_pd.send_keys(password)
login = browser.find_element_by_id(\'J-login\')
login.click()
logincode = 1
except Exception as e:
logincode = 0
print(e)
# 拉动滑块验证
def huakuai(browser):
global hkcode
hkcode = 0
try:
browser.implicitly_wait(5)
print(\'=====开始处理滑动验证码=====\')
track = [300, 400, 500]
for i in track:
try:
btn = browser.find_element_by_xpath(\'//*[@id="nc_1__scale_text"]/span\')
ActionChains(browser).drag_and_drop_by_offset(btn, i, 0).perform()
hkcode = 1
except:
time.sleep(2)
except Exception as e:
hkcode = 0
print(e)
# 疫情特殊要求
def yiqingyaoqiu(browser):
global yzcode
yzcode = 0
try:
browser.implicitly_wait(5)
try:
browser.find_element_by_xpath(\'/html/body/div[4]/div[2]/div[3]/a\').click()
yzcode = 1
except:
try:
browser.find_element_by_xpath(\'/html/body/div[2]/div[7]/div[2]/div[3]/a\').click()
yzcode = 1
except:
yzcode = 0
finally:
time.sleep(2)
except Exception as e:
yzcode = 0
print(e)
# 进入买票页面
def enterbuy(browser):
global xpcode
xpcode = 0
try:
browser.find_element_by_xpath(\'//*[@id="J-chepiao"]/a\').click()
browser.find_element_by_xpath(\'//*[@id="megamenu-3"]/div[1]/ul/li[1]/a\').click()
browser.find_element_by_xpath(\'//*[@id="qd_closeDefaultWarningWindowDialog_id"]\').click()
xpcode = 1
except Exception as e:
print(e)
xpcode = 0
# 将出发地、目的地、出发日期填进去
def input_info(browser):
global cpcode
cpcode = 0
date = \'2022-01-24\' # 填写购票日期
start_station = \'\' # 购票出发站,例如南京南
end_station = \'\' # 购票目的站
try:
print(\'=====开始买票=====\')
from_station = browser.find_element_by_xpath(\'//*[@id="fromStationText"]\')
from_station.send_keys(Keys.ENTER)
from_station.send_keys(Keys.CONTROL, \'a\')
from_station.send_keys(start_station, Keys.ENTER)
browser.implicitly_wait(5)
to_station = browser.find_element_by_xpath(\'//*[@id="toStationText"]\')
to_station.send_keys(Keys.ENTER)
to_station.send_keys(Keys.CONTROL, \'a\')
to_station.send_keys(end_station, Keys.ENTER)
browser.implicitly_wait(5)
start_date = browser.find_element_by_xpath(\'//*[@id="train_date"]\')
start_date.send_keys(Keys.ENTER)
start_date.send_keys(Keys.CONTROL, \'a\')
start_date.send_keys(Keys.CONTROL, \'x\')
start_date.send_keys(date, Keys.ENTER)
browser.implicitly_wait(5)
wait.WebDriverWait(browser, 3).until(EC.element_to_be_clickable((By.ID, \'query_ticket\'))).click()
cpcode = 1
except Exception as e:
print(e)
cpcode = 0
# 依次查找trains中的车次是否有票,有的话点击购买
def buy(browser):
global gmcode, code
gmcode = 0
code = 0
purpose = \'ADULT\' # 购买成人票,如果是学生票,需调整代码
names = [\'\'] # 填写购票人姓名,需要在你的乘车人管理里有的
trains = [] # 你想买的班次,例如\'D666\', \'G666\'
browser.implicitly_wait(5)
try:
trList = browser.find_elements_by_xpath(".//tbody[@id=\'queryLeftTable\']/tr[not(@datatran)]")
for tr in trList:
trainNum = tr.find_element_by_class_name("number").text
if trainNum in trains:
leftTicket = tr.find_element_by_xpath(".//td[4]").text
print(\'leftTicket\', leftTicket)
if leftTicket == \'有\' or leftTicket.isdigit():
orderBtn = tr.find_element_by_class_name("btn72")
orderBtn.click()
browser.implicitly_wait(5)
passengerLabels = browser.find_elements_by_xpath(".//ul[@id=\'normal_passenger_id\']/li/label")
for passengerLabel in passengerLabels:
name = passengerLabel.text
if name in names:
passengerLabel.click()
browser.implicitly_wait(20)
# 获取提交按钮
submitBtn = browser.find_element_by_id("submitOrder_id")
submitBtn.click()
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
time.sleep(2)
browser.implicitly_wait(20)
confirmBtn = browser.find_element_by_id("qr_submit_id")
confirmBtn.click()
code = 1
gmcode = 1
break
except Exception as e:
print(e)
gmcode = 0
def tuisong():
api = "https://sctapi.ftqq.com/*****.send" #*****替换成你的微信server酱的key,可以实现购票成功推送,然后你就自己去12306付款
title = \'购买成功\'
data =
"text": title
req = requests.post(api, data=data)
if __name__ == "__main__":
global logincode, yzcode, hkcode, xpcode, cpcode, gmcode, code
code = 0
logincode = 0
yzcode = 0
hkcode = 0
xpcode = 0
cpcode = 0
gmcode = 0
browser = init_program()
while code == 0:
while logincode == 0:
login(browser)
print(\'logincode:\', logincode)
while hkcode == 0:
huakuai(browser)
print(\'hkcode:\', hkcode)
while yzcode == 0:
yiqingyaoqiu(browser)
print(\'yzcode:\', yzcode)
while xpcode == 0:
enterbuy(browser)
print(\'xpcode:\', xpcode)
while cpcode == 0:
input_info(browser)
input_info(browser)#经测试,一次有可能不成功,我直接两次提交
print(\'cpcode:\', cpcode)
while gmcode == 0:
buy(browser)
print(\'gmcode:\', gmcode)
print(\'code:\', code)
if gmcode == 0:
browser.refresh()
time.sleep(2)
browser.find_element_by_xpath(\'//*[@id="qd_closeDefaultWarningWindowDialog_id"]\').click()
input_info(browser)
input_info(browser)
else:
try:
print(\'tijiao\')
confirmBtn = browser.find_element_by_id("qr_submit_id")
browser.implicitly_wait(20)
time.sleep(3)
confirmBtn.click()
except:pass
if code ==