- train.py
import configparser
import json
import os
import re
import time
from urllib.parse import quote
from urllib.parse import unquote
import requests
from my_12306.captcha import jsdati
'''
创建一个火车类
'''
class Train:
def __init__(self):
# 加载配置文件
self.__conf = configparser.ConfigParser()
self.__conf.read('conf.ini', encoding='utf-8')
# 出发地
self.__from_station = self.__conf.get('ticket', 'from_station')
# 目的地
self.__to_station = self.__conf.get('ticket', 'to_station')
# 出发日
self.__train_date = self.__conf.get('ticket', 'train_date')
# 车站代码 截止2018-05-14 版本号: 1.9053
with open('station_code.json', 'r', encoding='utf-8') as f:
self.__station_code = json.load(f)
self.img_path = os.path.join(os.path.dirname(__file__), 'code.png')
# 模拟浏览器
self.__headers = {
'User-Agent': self.__conf.get('headers', 'user_agent'),
'Referer': self.__conf.get('headers', 'referer'),
'Host': self.__conf.get('headers', 'host'),
}
# 禁用警告
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
# 创建 Session
self.__TicketSession = requests.Session()
self.__TicketSession.headers = self.__headers
self.__TicketSession.verify = False
self.__seat_type = '1'
def get_train(self):
temp_str = self.__TicketSession.get('https://kyfw.12306.cn/otn/leftTicket/init').text
pre_url = re.compile("CLeftTicketUrl = '(.*?)'").search(temp_str).group(1)
get_train_url = 'https://kyfw.12306.cn/otn/{}'.format(pre_url)
get_train_params = {
'leftTicketDTO.train_date': self.__train_date,
'leftTicketDTO.from_station': self.__station_code[self.__from_station],
'leftTicketDTO.to_station': self.__station_code[self.__to_station],
'purpose_codes': 'ADULT'
}
response = self.__TicketSession.get(url=get_train_url, params=get_train_params)
if response.status_code == 200:
return response.json()
def query_ticket_info(self):
js_info = self.get_train()
if not js_info['status']:
print('65 -> 查询余票失败!')
return
trains_list = js_info['data']['result']
for i in trains_list:
lst = i.split('|')
if lst[11] != 'Y':
continue
with open('conf.ini', 'w', encoding='utf-8') as f:
self.__conf.set('query_ticket_info', 'secretstr', unquote(lst[0]))
self.__conf.set('query_ticket_info', 'train_no', lst[2])
self.__conf.set('query_ticket_info', 'station_train_code', lst[3])
self.__conf.set('query_ticket_info', 'leftticket', unquote(lst[12]))
self.__conf.set('query_ticket_info', 'location_code', lst[15])
self.__conf.write(f)
return
def init_dc(self):
url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'
data = {
'_json_att': '',
}
response = self.__TicketSession.post(url=url, data=data)
if response.status_code == 200:
html = response.text
# 获取REPEAT_SUBMIT_TOKEN
regex = re.compile("var globalRepeatSubmitToken = '(\w+)'")
repeat_submit_token = re.findall(regex, html)[0]
# 获取key_check_isChange
key_check_is_change = re.findall("key_check_isChange':'(\w+)','leftDetails'", html)[0]
with open('conf.ini', 'w', encoding='utf-8') as f:
self.__conf.set('special', 'repeat_submit_token', repeat_submit_token)
self.__conf.set('special', 'key_check_ischange', key_check_is_change)
self.__conf.write(f)
def get_passenger(self):
url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'
data = {
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
}
response = self.__TicketSession.post(url=url, data=data)
# if response.status_code == 200:
# result = response.json()
# return result['data']['normal_passengers']
def get_img(self):
"""
获取验证码图片 -> 保存图片
"""
img_url = 'https://kyfw.12306.cn/passport/captcha/captcha-image'
img_data = {
'login_site': 'E',
'module': 'login',
'rand': 'sjrand',
}
response = self.__TicketSession.get(url=img_url, params=img_data)
if response.ok:
with open(self.img_path, 'wb') as f:
f.write(response.content)
def check_img(self):
"""
利用打码平台自动识别验证码
验证码正确 -> 执行 登陆
验证码错误 -> 重新获取验证码图片
"""
# 利用打码平台自动识别验证码
self.get_img()
print('正在识别验证码...')
code = jsdati.decode(self.img_path)
print(code)
check_img_url = 'https://kyfw.12306.cn/passport/captcha/captcha-check'
check_img_data = {
'answer': code,
'login_site': 'E',
'rand': 'sjrand'
}
response = self.__TicketSession.post(url=check_img_url, data=check_img_data)
if response.status_code == 200:
result = response.json()
print('146 - >', result['result_message'])
if result['result_code'] == '4':
self.login()
elif result['result_code'] == -4:
exit(1)
else:
jsdati.report_error()
time.sleep(1)
self.check_img()
def login(self):
"""
登陆12306
登陆成功 -> 执行 验证登陆
"""
login_url = 'https://kyfw.12306.cn/passport/web/login'
login_data = {
'username': self.__conf.get('user_info', 'username'),
'password': self.__conf.get('user_info', 'password'),
'appid': 'otn',
}
response = self.__TicketSession.post(url=login_url, data=login_data)
if response.status_code == 200:
response.encoding = 'utf-8' # 这里必须加, 否则抛出异常 JSONDecodeError
result = response.json()
print('170 ->', result['result_message'])
if result['result_code'] == 0:
self.check_login()
def check_login(self):
"""
验证登陆 -> 验证通过 newapptk -> 验证通过 username=自己的姓名 -> 再次 检测登陆
:return:
"""
check_login_url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'
check_login_data = {
'appid': 'otn'
}
response = self.__TicketSession.post(url=check_login_url, data=check_login_data)
if response.status_code == 200:
result = response.json()
print('186 ->', result['result_message'])
if result['result_code'] == 0:
newapptk = result['newapptk']
check_login_url = 'https://kyfw.12306.cn/otn/uamauthclient'
check_login_data = {
'tk': newapptk
}
response = self.__TicketSession.post(url=check_login_url, data=check_login_data)
if response.status_code == 200:
print('195 ->', result['result_message'])
if result['result_code'] == 0:
self.check_user()
def check_user(self):
"""
检查用户登陆 -> 提交订单请求
"""
check_user_url = 'https://kyfw.12306.cn/otn/login/checkUser'
check_user_data = {
'_json_att': ''
}
response = self.__TicketSession.post(url=check_user_url, data=check_user_data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('211 ->', result)
self.submit_order_request()
def submit_order_request(self):
self.query_ticket_info()
url = 'https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'
data = {
'secretStr': self.__conf.get('query_ticket_info', 'secretstr'),
'train_date': self.__train_date,
'back_train_date': time.strftime('%Y-%m-%d'),
'tour_flag': 'dc',
'purpose_codes': 'ADULT',
'query_from_station_name': self.__from_station,
'query_to_station_name': self.__to_station,
'undefined': '',
}
response = self.__TicketSession.post(url=url, data=data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('231 ->', result)
self.check_order_info()
def check_order_info(self):
self.init_dc()
# self.get_passenger()
url = 'https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'
data = {
'cancel_flag': '2', # 固定值
'bed_level_order_num': '000000000000000000000000000000', # 固定值
# passengerTicketStr 和oldPassengerStr 均为旅客信息字符串, 不要含有空格
# 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N)
'passengerTicketStr': self.__conf.get('passenger', 'passengerticketstr'),
# 乘客名,证件类型,证件号,乘客类型
'oldPassengerStr': self.__conf.get('passenger', 'oldpassengerstr'),
'tour_flag': 'dc',
'randCode': '',
'whatsSelect': '1',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
}
response = self.__TicketSession.post(url=url, data=data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('255 ->', result)
self.get_queue_count()
def get_queue_count(self):
url = 'https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'
tmp = time.strftime('%a %b %d %Y 00:00:00 %z', time.strptime(self.__train_date, '%Y-%m-%d')).split('+')
data = {
'train_date': tmp[0] + 'GMT+' + tmp[1] + ' (中国标准时间)',
'train_no': self.__conf.get('query_ticket_info', 'train_no'),
'stationTrainCode': self.__conf.get('query_ticket_info', 'station_train_code'),
'seatType': self.__seat_type,
'fromStationTelecode': self.__station_code[self.__from_station],
'toStationTelecode': self.__station_code[self.__to_station],
'leftTicket': quote(self.__conf.get('query_ticket_info', 'leftticket')),
'purpose_codes': '00',
'train_location': self.__conf.get('query_ticket_info', 'location_code'),
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
}
response = self.__TicketSession.post(url=url, data=data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('278 ->', result)
self.confirm_single_for_queue()
def confirm_single_for_queue(self):
url = 'https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'
data = {
'passengerTicketStr': self.__conf.get('passenger', 'passengerticketstr'),
'oldPassengerStr': self.__conf.get('passenger', 'oldpassengerstr'),
'randCode': '',
'purpose_codes': '00',
'key_check_isChange': self.__conf.get('special', 'key_check_ischange'),
'leftTicketStr': quote(self.__conf.get('query_ticket_info', 'leftticket')),
'train_location': self.__conf.get('query_ticket_info', 'location_code'),
'choose_seats': '',
'seatDetailType': '000',
'whatsSelect': '1',
'roomType': '00',
'dwAll': 'N',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
}
response = self.__TicketSession.post(url=url, data=data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('303 ->', result)
self.query_wait_time()
def query_wait_time(self):
url = 'https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime'
data = {
'random': int(time.time() * 1000),
'tourFlag': 'dc',
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
}
response = self.__TicketSession.get(url=url, params=data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('318 ->', result)
# response = self.__TicketSession.get(url=url, params=data)
# if response.status_code == 200:
# result = response.json()
# if result['status']:
# print('323 ->', result['data']['orderId'])
# self.result_order_for_queue(result['data']['orderId'])
def result_order_for_queue(self, order_sequence_no):
url = 'https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue'
data = {
'orderSequence_no': order_sequence_no,
'_json_att': '',
'REPEAT_SUBMIT_TOKEN': self.__conf.get('special', 'repeat_submit_token'),
}
response = self.__TicketSession.post(url=url, data=data)
if response.status_code == 200:
result = response.json()
if result['status']:
print('337 ->', result)
def buy_ticket(self):
self.query_ticket_info()
self.check_img()
if __name__ == '__main__':
train = Train()
train.buy_ticket()
12306.jpg
最后更新时间:2018-05-15 0:15:23
网友评论