使用Python抢票回家
春节是中国人最重要的传统节日之一,也是全球最大规模的人口迁徙之一。对于不能提前预订车票来回家的人来说,抢票是他们最紧迫的任务之一。利用Python,您可以写一个简单但有效的脚本来帮助您抢票回家。
准备工作
在编写抢票脚本之前,您需要准备以下内容:
一个12306账户
一个能够发送http请求的Python库,例如requests
一个用于解析HTML的Python库,例如beautifulsoup4
一个支持图像识别的Python库,例如pytesseract和pillow
登录12306
登录12306是使用Python抢票的第一步。在这里,我们将使用requests库发送POST请求来登录12306:
import requests
session = requests.session()
login_url = 'https://kyfw.12306.cn/otn/login/init'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
username = 'your_username'
password = 'your_password'
# 发送GET请求,获取cookie信息
response = session.get(login_url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser')
login_form = soup.find('form', id='loginForm')
login_url = login_form['action']
login_random_code = login_form['data-loginrand']
# 发送POST请求,进行登录
data = {
'username': username,
'password': password,
'appid': 'otn',
'randomCode': '',
'isAutoSug': 'N',
'loginRand': login_random_code
}
login_headers = headers.copy()
login_headers.update({'Referer': 'https://kyfw.12306.cn/otn/login/init'})
response = session.post(login_url, data=data, headers=login_headers)
在以上代码中,我们使用了requests库的session功能来保持会话状态,并且在发送POST请求时添加必要的头部信息。注意,我们需要通过GET请求来获取cookie信息、登录URL和随机码等必要信息。
查询余票
查询余票是抢票的核心步骤之一。以下是查询余票的代码:
query_url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ'
def query_ticket(start_station, end_station, date):
params = {
'leftTicketDTO.train_date': date,
'leftTicketDTO.from_station': start_station,
'leftTicketDTO.to_station': end_station,
'purpose_codes': 'ADULT'
}
response = session.get(query_url, params=params, headers=headers, verify=False)
data = response.json()
ticket_list = data['data']['result']
for ticket_info in ticket_list:
ticket_info = ticket_info.split('|')
if ticket_info[0] != '':
# 以下是您需要关注的列车信息
train_no = ticket_info[3] # 车次
from_station_name = ticket_info[6] # 出发站
to_station_name = ticket_info[7] # 到达站
start_time = ticket_info[8] # 出发时间
arrival_time = ticket_info[9] # 到达时间
duration = ticket_info[10] # 历时
swz_num = ticket_info[32] or '--' # 商务座/特等座
tz_num = ticket_info[25] or '--' # 特等座/商务座
zy_num = ticket_info[31] or '--' # 一等座
ze_num = ticket_info[30] or '--' # 二等座
gr_num = ticket_info[21] or '--' # 高级软卧
rw_num = ticket_info[23] or '--' # 软卧
dw_num = ticket_info[27] or '--' # 动卧
yw_num = ticket_info[28] or '--' # 硬卧
rz_num = ticket_info[24] or '--' # 软座
yz_num = ticket_info[29] or '--' # 硬座
wz_num = ticket_info[26] or '--' # 无座
首先,我们需要确定查询余票的URL,默认是queryZ。在查询余票的请求中,我们需要指定出发日期、出发站和到达站等信息。发送请求后,我们需要对返回结果进行解析,以获取需要的信息。在以上代码中,我们只获取了每趟列车的车次、出发站、到达站、出发时间、到达时间和票量等信息。
选择座位
为了抢到票,我们还需要选择我们需要的座位类型。以下是选择座位的代码:
def submit_order(train_no, from_station_name, to_station_name, start_time, date):
submit_url = 'https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'
data = {
'secretStr': '',
'train_date': date,
'back_train_date': '',
'tour_flag': 'dc',
'purpose_codes': 'ADULT',
'query_from_station_name': from_station_name,
'query_to_station_name': to_station_name,
'undefined': ''
}
response = session.post(submit_url, data=data, headers=headers, verify=False)
if response.status_code == 200:
initdc_url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
data = {
'_json_att': ''
}
response = session.post(initdc_url, data=data, headers=headers, verify=False)
if response.status_code == 200:
# 进行图像识别
img_url = 'https://kyfw.12306.cn/otn/passcodeNew/getPassCodeNew?module=passenger&rand=randp&0.6034260117320401'
response = session.get(img_url, headers=headers, verify=False)
with open('code.png', 'wb') as f:
f.write(response.content)
img = Image.open('code.png')
code = pytesseract.image_to_string(img)
code = code.strip()
print(code)
在以上代码中,我们首先发送一个submitOrderRequest请求来获取secretStr等必要信息。然后,我们又发送了一个get请求,来获取用于显示验证码的图片,并使用pytesseract进行图像识别。等到我们成功填写了验证码之后,我们就可以提交订单了。
提交订单
以下是提交订单的代码:
def check_order_info():
checkorder_url = 'https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'
data = {
'cancel_flag': '2',
'bed_level_order_num': '000000000000000000000000000000',
'passengerTicketStr': '',
'oldPassengerStr': '',
'tour_flag': 'dc',
'randCode': code,
'whatsSelect': '1',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': ''
}
response = session.post(checkorder_url, data=data, headers=headers, verify=False)
print(response.content)
def confirm_order():
confirm_url = 'https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'
data = {
'passengerTicketStr': '',
'oldPassengerStr': '',
'randCode': code,
'purpose_codes': 'ADULT',
'key_check_isChange': 'B0E67E1FEDB9DC2A74AA7B69771BB08024BBD37E704AE84DCB067D5D',
'leftTicketStr': '',
'train_location': '',
'choose_seats': '',
'seatDetailType': '000',
'whatsSelect': '1',
'roomType': '00',
'dwAll': 'N',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': ''
}
response = session.post(confirm_url, data=data, headers=headers, verify=False)
print(response.content)
def get_queue_count(train_no, from_station_name, to_station_name, start_time, seat_type, date):
getqueuecount_url = 'https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'
data = {
'train_date': date,
'train_no': train_no,
'stationTrainCode': 'G1234', # 从查询余票的结果中获取
'seatType': seat_type,
'fromStationTelecode': 'VNP', # 从查询余票的结果中获取
'toStationTelecode': 'NJH', # 从查询余票的结果中获取
'leftTicket': '',
'purpose_codes': '00',
'train_location': 'P2',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': ''
}
response = session.post(getqueuecount_url, data=data, headers=headers, verify=False)
print(response.content)
check_order_info()
confirm_order()
get_queue_count(train_no, from_station_name, to_station_name, start_time, seat_type, date)
最后,我们需要完成订单的确认和队列数量的查询。在以上代码中,我们首先检查并确认订单信息,然后提交订单,最后,我们获取队列数量以进一步确认是否有座位。
总结
使用Python抢票可能需要一些前期准备和学习,但一旦您了解了基本原理和如何使用Python进行自动化脚本编写,您将更容易地抢到票。