From 27a5a13c0a5e158974dff2b9738d06b13d2d2a65 Mon Sep 17 00:00:00 2001 From: Jalin Date: Mon, 7 Jan 2019 21:14:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=87=AA=E5=8A=A8=E4=B8=8B?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- py12306/config.py | 13 +- py12306/helpers/api.py | 6 + py12306/helpers/func.py | 4 +- py12306/log/order_log.py | 42 +++++ py12306/log/query_log.py | 2 +- py12306/log/user_log.py | 2 + py12306/order/order.py | 335 ++++++++++++++++++++++++++++++++++++--- py12306/query/job.py | 46 +++++- py12306/query/query.py | 2 +- py12306/user/job.py | 34 ++++ py12306/user/user.py | 21 ++- 11 files changed, 471 insertions(+), 36 deletions(-) create mode 100644 py12306/log/order_log.py diff --git a/py12306/config.py b/py12306/config.py index f90743e..ae7836c 100644 --- a/py12306/config.py +++ b/py12306/config.py @@ -24,16 +24,27 @@ AUTO_CODE_ACCOUNT = { } SEAT_TYPES = { + '特等座': 25, '商务座': 32, '一等座': 31, '二等座': 30, - '特等座': 25, '软卧': 23, '硬卧': 28, '硬座': 29, '无座': 26, } +ORDER_SEAT_TYPES = { + '特等座': 'P', + '商务座': 9, + '一等座': 'M', + '二等座': 'O', + '软卧': 4, + '硬卧': 3, + '硬座': 1, + '无座': 1, +} + PROJECT_DIR = path.dirname(path.dirname(path.abspath(__file__))) + '/' # Query diff --git a/py12306/helpers/api.py b/py12306/helpers/api.py index 9e21f92..dad4538 100644 --- a/py12306/helpers/api.py +++ b/py12306/helpers/api.py @@ -43,6 +43,12 @@ API_USER_INFO = { 'url': BASE_URL_OF_12306 + '/otn/modifyUser/initQueryUserInfoApi' } API_USER_PASSENGERS = BASE_URL_OF_12306 + '/otn/confirmPassenger/getPassengerDTOs' +API_SUBMIT_ORDER_REQUEST = BASE_URL_OF_12306 + '/otn/leftTicket/submitOrderRequest' +API_CHECK_ORDER_INFO = BASE_URL_OF_12306 + '/otn/confirmPassenger/checkOrderInfo' +API_INITDC_URL = BASE_URL_OF_12306 + '/otn/confirmPassenger/initDc' # 生成订单时需要先请求这个页面 +API_GET_QUEUE_COUNT = BASE_URL_OF_12306 + '/otn/confirmPassenger/getQueueCount' +API_CONFIRM_SINGLE_FOR_QUEUE = BASE_URL_OF_12306 + '/otn/confirmPassenger/confirmSingleForQueue' +API_QUERY_ORDER_WAIT_TIME = BASE_URL_OF_12306 + '/otn/confirmPassenger/queryOrderWaitTime?{}' # 排队查询 urls = { "auth": { # 登录接口 diff --git a/py12306/helpers/func.py b/py12306/helpers/func.py index b44bace..f00fb48 100644 --- a/py12306/helpers/func.py +++ b/py12306/helpers/func.py @@ -59,8 +59,10 @@ def get_interval_num(interval, decimal=2): return round(random.uniform(interval.get('min'), interval.get('max')), decimal) -def stay_second(second): +def stay_second(second, call_back=None): sleep(second) + if call_back: + return call_back() def is_main_thread(): diff --git a/py12306/log/order_log.py b/py12306/log/order_log.py new file mode 100644 index 0000000..7836a11 --- /dev/null +++ b/py12306/log/order_log.py @@ -0,0 +1,42 @@ +from py12306.log.base import BaseLog +from py12306.helpers.func import * + + +@singleton +class OrderLog(BaseLog): + MESSAGE_REQUEST_INIT_DC_PAGE_FAIL = '请求初始化订单页面失败' + + MESSAGE_SUBMIT_ORDER_REQUEST_FAIL = '提交订单失败,错误原因 {}' + MESSAGE_SUBMIT_ORDER_REQUEST_SUCCESS = '提交订单成功' + MESSAGE_CHECK_ORDER_INFO_FAIL = '检查订单失败,错误原因 {}' + MESSAGE_CHECK_ORDER_INFO_SUCCESS = '检查订单成功' + + MESSAGE_GET_QUEUE_COUNT_SUCCESS = '排队成功,你当前排在第 {} 位, 余票还剩余 {} 张' + MESSAGE_GET_QUEUE_COUNT_FAIL = '排队失败,错误原因 {}' + + MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_SUCCESS = '# 提交订单成功!#' + MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_ERROR = '提交订单出错,错误原因 {}' + MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_FAIL = '提交订单失败,错误原因 {}' + + MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING = '排队等待中,预计还需要 {} 秒' + MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL = '排队失败,错误原因 {}' + MESSAGE_QUERY_ORDER_WAIT_TIME_INFO = '第 {} 次排队,请耐心等待' + + MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE = '车票购买成功!' + MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT = '请及时器登录12306,打开 \'未完成订单\',在30分钟内完成支付!' + + + @classmethod + def print_passenger_did_deleted(cls, passengers): + self = cls() + result = [passenger.get('name') + '(' + passenger.get('type_text') + ')' for passenger in passengers] + self.add_quick_log('# 删减后的乘客列表 {} #'.format(', '.join(result))) + self.flush() + return self + + @classmethod + def print_ticket_did_ordered(cls, order_id): + self = cls() + self.add_quick_log('# 车票购买成功,订单号{} #'.format(order_id)) + self.flush() + return self diff --git a/py12306/log/query_log.py b/py12306/log/query_log.py index c10346f..1a53eb8 100644 --- a/py12306/log/query_log.py +++ b/py12306/log/query_log.py @@ -63,7 +63,7 @@ class QueryLog(BaseLog): self.add_quick_log( '余票数小于乘车人数,当前余票数: {rest_num}, 实际人数 {actual_num}, 删减人车人数到: {take_num}'.format(rest_num=rest_num, actual_num=job.member_num, - take=job.member_num_take)) + take_num=job.member_num_take)) self.flush() return self diff --git a/py12306/log/user_log.py b/py12306/log/user_log.py index a04ee5c..1a8c126 100644 --- a/py12306/log/user_log.py +++ b/py12306/log/user_log.py @@ -17,6 +17,8 @@ class UserLog(BaseLog): MESSAGE_GET_USER_PASSENGERS_FAIL = '获取用户乘客列表失败,错误原因: {} {} 秒后重试' MESSAGE_USER_PASSENGERS_IS_INVALID = '乘客信息校验失败,在账号 {} 中未找到该乘客: {}' + MESSAGE_WAIT_USER_INIT_COMPLETE = '未找到可用账号或用户正在初始化,{} 秒重试' + def __init__(self): super().__init__() self.init_data() diff --git a/py12306/order/order.py b/py12306/order/order.py index 204451f..e2e553e 100644 --- a/py12306/order/order.py +++ b/py12306/order/order.py @@ -1,34 +1,329 @@ +import urllib +import random + +from py12306.config import UserType +from py12306.helpers.api import * from py12306.helpers.app import * from py12306.helpers.func import * +from py12306.log.order_log import OrderLog from py12306.log.user_log import UserLog -from py12306.user.job import UserJob + + +# from py12306.query.job import Job +# from py12306.user.job import UserJob class Order: """ 处理下单 """ - heartbeat = 60 * 2 - users = [] + session = None + query_ins = None + user_ins = None - def __init__(self): + passenger_ticket_str = '' + old_passenger_str = '' + + is_need_auth_code = False + + max_queue_wait = 120 + current_queue_wait = 0 + retry_time = 3 + wait_queue_interval = 3 + + def __init__(self, query, user): + self.session = user.session + # assert isinstance(query, Job) # 循环引用 + # assert isinstance(user, UserJob) + self.query_ins = query + self.user_ins = user + + self.make_passenger_ticket_str() + + def order(self): + """ + 开始下单 + 下单模式 暂时不清楚,使用正常步骤下单 + :return: + """ + self.normal_order() pass - @classmethod - def run(cls): - self = cls() - app_available_check() - self.start() - pass + def normal_order(self): + if not self.submit_order_request(): return + if not self.user_ins.request_init_dc_page(): return + if not self.check_order_info(): return + if not self.get_queue_count(): return + if not self.confirm_single_for_queue(): return + order_id = self.query_order_wait_time() + if order_id: # 发送通知 + OrderLog.print_ticket_did_ordered(order_id) + OrderLog.notification(OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE, + OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT) - def start(self): - self.init_users() - UserLog.print_init_users(users=self.users) - # 多线程维护用户 - create_thread_and_run(jobs=self.users, callback_name='run', wait=False) + def submit_order_request(self): + data = { + 'secretStr': urllib.parse.unquote(self.query_ins.get_info_of_secret_str()), # 解密 + 'train_date': self.query_ins.left_date, # 出发时间 + 'back_train_date': self.query_ins.left_date, # 返程时间 + 'tour_flag': 'dc', # 旅途类型 + 'purpose_codes': 'ADULT', # 成人 | 学生 + 'query_from_station_name': self.query_ins.left_station, + 'query_to_station_name': self.query_ins.arrive_station, + } + response = self.session.post(API_SUBMIT_ORDER_REQUEST, data) + result = response.json() + if result.get('data') == 'N': + OrderLog.add_quick_log(OrderLog.MESSAGE_SUBMIT_ORDER_REQUEST_SUCCESS).flush() + return True + else: + OrderLog.add_quick_log( + OrderLog.MESSAGE_SUBMIT_ORDER_REQUEST_FAIL.format(result.get('messages', '-'))).flush() + return False - def init_users(self): - accounts = config.USER_ACCOUNTS - for account in accounts: - user = UserJob(info=account, user=self) - self.users.append(user) + def check_order_info(self): + """ + cancel_flag=2 + bed_level_order_num=000000000000000000000000000000 + passengerTicketStr= + tour_flag=dc + randCode= + whatsSelect=1 + _json_att= + REPEAT_SUBMIT_TOKEN=458bf1b0a69431f34f9d2e9d3a11cfe9 + :return: + """ + data = { # + 'cancel_flag': 2, + 'bed_level_order_num': '000000000000000000000000000000', + 'passengerTicketStr': self.passenger_ticket_str, + 'oldPassengerStr': self.old_passenger_str, + 'tour_flag': 'dc', + 'randCode': '', + 'whatsSelect': '1', + '_json_att': '', + 'REPEAT_SUBMIT_TOKEN': self.user_ins.global_repeat_submit_token + } + response = self.session.post(API_CHECK_ORDER_INFO, data) + result = response.json() + if 'data' in result and result['data'].get('submitStatus'): # 成功 + OrderLog.add_quick_log(OrderLog.MESSAGE_CHECK_ORDER_INFO_SUCCESS).flush() + if result['data'].get("ifShowPassCode") != 'N': + self.is_need_auth_code = True + return True + else: + result_data = result.get('data', {}) + OrderLog.add_quick_log(OrderLog.MESSAGE_CHECK_ORDER_INFO_FAIL.format( + result_data.get('errMsg', result.get('messages', '-')) + )).flush() + return False + + def get_queue_count(self): + """ + 获取队列人数 + train_date Mon Jan 01 2019 00:00:00 GMT+0800 (China Standard Time) + train_no 630000Z12208 + stationTrainCode Z122 + seatType 4 + fromStationTelecode GZQ + toStationTelecode RXW + leftTicket CmDJZYrwUoJ1jFNonIgPzPFdMBvSSE8xfdUwvb2lq8CCWn%2Bzk1vM3roJaHk%3D + purpose_codes 00 + train_location QY + _json_att + REPEAT_SUBMIT_TOKEN 0977caf26f25d1da43e3213eb35ff87c + :return: + """ + data = { # + 'train_date': '{} 00:00:00 GMT+0800 (China Standard Time)'.format( + datetime.datetime.today().strftime("%a %h %d %Y")), + 'train_no': self.user_ins.ticket_info_for_passenger_form['queryLeftTicketRequestDTO']['train_no'], + 'stationTrainCode': self.user_ins.ticket_info_for_passenger_form['queryLeftTicketRequestDTO'][ + 'station_train_code'], + 'seatType': self.query_ins.current_order_seat, + 'fromStationTelecode': self.user_ins.ticket_info_for_passenger_form['queryLeftTicketRequestDTO'][ + 'from_station'], + 'toStationTelecode': self.user_ins.ticket_info_for_passenger_form['queryLeftTicketRequestDTO'][ + 'to_station'], + 'leftTicket': self.user_ins.ticket_info_for_passenger_form['leftTicketStr'], + 'purpose_codes': self.user_ins.ticket_info_for_passenger_form['purpose_codes'], + 'train_location': self.user_ins.ticket_info_for_passenger_form['train_location'], + '_json_att': '', + 'REPEAT_SUBMIT_TOKEN': self.user_ins.global_repeat_submit_token, + } + response = self.session.post(API_GET_QUEUE_COUNT, data) + result = response.json() + if 'data' in result and ('countT' in result['data'] or 'ticket' in result['data']): # 成功 + """ + "data": { + "count": "66", + "ticket": "0,73", + "op_2": "false", + "countT": "0", + "op_1": "true" + } + """ + ticket = result['data']['ticket'].split(',') # 暂不清楚具体作用 + ticket_number = sum(map(int, ticket)) + current_position = int(data.get('countT', 0)) + OrderLog.add_quick_log( + OrderLog.MESSAGE_GET_QUEUE_COUNT_SUCCESS.format(current_position, ticket_number)).flush() + return True + else: + # 加入小黑屋 + OrderLog.add_quick_log(OrderLog.MESSAGE_GET_QUEUE_COUNT_FAIL.format( + result.get('messages', result.get('validateMessages', '-')))).flush() + return False + + def confirm_single_for_queue(self): + """ + 确认排队 + passengerTicketStr + oldPassengerStr + randCode + purpose_codes 00 + key_check_isChange FEE6C6634A3EAA93E1E6CFC39A99E555A92E438436F18AFF78837CDB + leftTicketStr CmDJZYrwUoJ1jFNonIgPzPFdMBvSSE8xfdUwvb2lq8CCWn%2Bzk1vM3roJaHk%3D + train_location QY + choose_seats + seatDetailType 000 + whatsSelect 1 + roomType 00 + dwAll N + _json_att + REPEAT_SUBMIT_TOKEN 0977caf26f25d1da43e3213eb35ff87c + :return: + """ + data = { # + 'passengerTicketStr': self.passenger_ticket_str, + 'oldPassengerStr': self.old_passenger_str, + 'randCode': '', + 'purpose_codes': self.user_ins.ticket_info_for_passenger_form['purpose_codes'], + 'key_check_isChange': self.user_ins.ticket_info_for_passenger_form['key_check_isChange'], + 'leftTicketStr': self.user_ins.ticket_info_for_passenger_form['leftTicketStr'], + 'train_location': self.user_ins.ticket_info_for_passenger_form['train_location'], + 'choose_seats': '', + 'seatDetailType': '000', + 'whatsSelect': '1', + 'roomType': '00', + 'dwAll': 'N', + '_json_att': '', + 'REPEAT_SUBMIT_TOKEN': self.user_ins.global_repeat_submit_token, + } + + if self.is_need_auth_code: # 目前好像是都不需要了,有问题再处理 + pass + + response = self.session.post(API_CONFIRM_SINGLE_FOR_QUEUE, data) + result = response.json() + + if 'data' in result: + """ + "data": { + "submitStatus": true + } + """ + if result['data'].get('submitStatus'): # 成功 + OrderLog.add_quick_log(OrderLog.MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_SUCCESS).flush() + return True + else: + # 加入小黑屋 TODO + OrderLog.add_quick_log( + OrderLog.MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_ERROR.format(result['data'].get('errMsg', '-'))).flush() + else: + OrderLog.add_quick_log(OrderLog.MESSAGE_CONFIRM_SINGLE_FOR_QUEUE_FAIL.format( + result.get('messages', '-'))).flush() + return False + + def query_order_wait_time(self): + """ + 排队查询 + random 1546849953542 + tourFlag dc + _json_att + REPEAT_SUBMIT_TOKEN 0977caf26f25d1da43e3213eb35ff87c + :return: + """ + self.current_queue_wait = self.max_queue_wait + while self.current_queue_wait: + self.current_queue_wait -= 1 + # TODO 取消超时订单,待优化 + data = { # + 'random': str(random.random())[2:], + 'tourFlag': 'dc', + '_json_att': '', + 'REPEAT_SUBMIT_TOKEN': self.user_ins.global_repeat_submit_token, + } + + response = self.session.get(API_QUERY_ORDER_WAIT_TIME.format(urllib.parse.urlencode(data))) + result = response.json() + + if result.get('status') and 'data' in result: + """ + "data": { + "queryOrderWaitTimeStatus": true, + "count": 0, + "waitTime": -1, + "requestId": 6487958947291482523, + "waitCount": 0, + "tourFlag": "dc", + "orderId": "E222646122" + } + """ + result_data = result['data'] + order_id = result_data.get('orderId') + if order_id: # 成功 + return order_id + elif result_data.get('waitTime') and result_data.get('waitTime') >= 0: + OrderLog.add_quick_log( + OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING.format(result_data.get('waitTime'))).flush() + elif result_data.get('msg'): # 失败 + OrderLog.add_quick_log( + OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL.format(result_data.get('msg', '-'))).flush() + return False + elif result.get('messages') or result.get('validateMessages'): + OrderLog.add_quick_log(OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL.format( + result.get('messages', result.get('validateMessages')))).flush() + else: + pass + OrderLog.add_quick_log(OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_INFO.format(self.current_queue_wait)).flush() + stay_second(self.wait_queue_interval) + + return False + + def make_passenger_ticket_str(self): + """ + 生成提交车次的内容 + 格式: + 1(seatType),0,1(车票类型:ticket_type_codes),张三(passenger_name),1(证件类型:passenger_id_type_code),xxxxxx(passenger_id_no),xxxx(mobile_no),N + passengerTicketStr: + 张三(passenger_name),1(证件类型:passenger_id_type_code),xxxxxx(passenger_id_no),1_ + oldPassengerStr + :return: + """ + passenger_tickets = [] + old_passengers = [] + available_passengers = self.query_ins.passengers + if len(available_passengers) > self.query_ins.member_num_take: # 删除人数 + available_passengers = available_passengers[0:self.query_ins.member_num_take] + OrderLog.print_passenger_did_deleted(available_passengers) + + for passenger in available_passengers: + tmp_str = '{seat_type},0,{passenger_type},{passenger_name},{passenger_id_card_type},{passenger_id_card},{passenger_mobile},N_'.format( + seat_type=self.query_ins.current_order_seat, passenger_type=passenger['type'], + passenger_name=passenger['name'], + passenger_id_card_type=passenger['id_card_type'], passenger_id_card=passenger['id_card'], + passenger_mobile=passenger['mobile'] + ) + passenger_tickets.append(tmp_str) + + if int(passenger['type']) != UserType.CHILD: + tmp_old_str = '{passenger_name},{passenger_id_card_type},{passenger_id_card},{passenger_type}_'.format( + passenger_name=passenger['name'], + passenger_id_card_type=passenger['id_card_type'], passenger_id_card=passenger['id_card'], + passenger_type=passenger['type'], + ) + old_passengers.append(tmp_old_str) + + self.passenger_ticket_str = ''.join(passenger_tickets).rstrip('_') + self.old_passenger_str = ''.join(old_passengers).rstrip('_') + '__ _ _' # 不加后面请求会出错 diff --git a/py12306/query/job.py b/py12306/query/job.py index 2041515..1c5e941 100644 --- a/py12306/query/job.py +++ b/py12306/query/job.py @@ -3,6 +3,7 @@ from py12306.helpers.station import Station from py12306.log.query_log import QueryLog from py12306.helpers.func import * from py12306.log.user_log import UserLog +from py12306.order.order import Order from py12306.user.user import User @@ -12,6 +13,7 @@ class Job: """ left_dates = [] + left_date = None left_station = '' arrive_station = '' left_station_code = '' @@ -19,6 +21,8 @@ class Job: account_key = 0 allow_seats = [] + current_seat = None + current_order_seat = None allow_train_numbers = [] members = [] member_num = 0 @@ -32,10 +36,12 @@ class Job: ticket_info = {} INDEX_TICKET_NUM = 11 INDEX_TRAIN_NUMBER = 3 + INDEX_TRAIN_NO = 2 INDEX_LEFT_DATE = 13 INDEX_LEFT_STATION = 6 # 4 5 始发 终点 INDEX_ARRIVE_STATION = 7 INDEX_ORDER_TEXT = 1 # 下单文字 + INDEX_SECRET_STR = 0 def __init__(self, info, query): self.left_dates = info.get('left_dates') @@ -67,22 +73,20 @@ class Job: :param job: :return: """ - if not self.passengers: - User.check_members(self.members, self.account_key, call_back=self.set_passengers) - QueryLog.print_job_start() for date in self.left_dates: + self.left_date = date response = self.query_by_date(date) self.handle_response(response) self.safe_stay() if is_main_thread(): - QueryLog.flush(sep='\t\t') + QueryLog.flush(sep='\t') else: QueryLog.add_log('\n') if is_main_thread(): QueryLog.add_quick_log('').flush() else: - QueryLog.flush(sep='\t\t') + QueryLog.flush(sep='\t') def query_by_date(self, date): """ @@ -116,12 +120,14 @@ class Job: self.get_info_of_ticket_num())) if not self.is_has_ticket(ticket_info): continue - allow_seats = self.allow_seats if self.allow_seats else list(config.SEAT_TYPES.values()) # 未设置 则所有可用 + allow_seats = self.allow_seats if self.allow_seats else list( + config.SEAT_TYPES.values()) # 未设置 则所有可用 TODO 合法检测 self.handle_seats(allow_seats, ticket_info) def handle_seats(self, allow_seats, ticket_info): for seat in allow_seats: # 检查座位是否有票 - ticket_of_seat = ticket_info[get_seat_number_by_name(seat)] + self.set_seat(seat) + ticket_of_seat = ticket_info[self.current_seat] if not self.is_has_ticket_by_seat(ticket_of_seat): # 座位是否有效 continue QueryLog.print_ticket_seat_available(left_date=self.get_info_of_left_date(), @@ -139,7 +145,9 @@ class Job: QueryLog.print_ticket_available(left_date=self.get_info_of_left_date(), train_number=self.get_info_of_train_number(), rest_num=ticket_of_seat) - print('检查完成 开始提交订单') + self.check_passengers() + order = Order(user=self.get_user(), query=self) + order.order() def get_results(self, response): """ @@ -179,6 +187,22 @@ class Job: UserLog.print_user_passenger_init_success(passengers) self.passengers = passengers + def set_seat(self, seat): + self.current_seat = get_seat_number_by_name(seat) + self.current_order_seat = config.ORDER_SEAT_TYPES[seat] + + def get_user(self): + user = User.get_user(self.account_key) + if not user.check_is_ready(): + # TODO user is not ready + pass + return user + + def check_passengers(self): + if not self.passengers: + User.check_members(self.members, self.account_key, call_back=self.set_passengers) + return True + # 提供一些便利方法 def get_info_of_left_date(self): return self.ticket_info[self.INDEX_LEFT_DATE] @@ -189,6 +213,9 @@ class Job: def get_info_of_train_number(self): return self.ticket_info[self.INDEX_TRAIN_NUMBER] + def get_info_of_train_no(self): + return self.ticket_info[self.INDEX_TRAIN_NO] + def get_info_of_left_station(self): return Station.get_station_name_by_key(self.ticket_info[self.INDEX_LEFT_STATION]) @@ -197,3 +224,6 @@ class Job: def get_info_of_order_text(self): return self.ticket_info[self.INDEX_ORDER_TEXT] + + def get_info_of_secret_str(self): + return self.ticket_info[self.INDEX_SECRET_STR] diff --git a/py12306/query/query.py b/py12306/query/query.py index 9de27cc..954aba4 100644 --- a/py12306/query/query.py +++ b/py12306/query/query.py @@ -31,7 +31,7 @@ class Query: pass def start(self): - return # DEBUG + # return # DEBUG self.init_jobs() QueryLog.print_init_jobs(jobs=self.jobs) while True: diff --git a/py12306/user/job.py b/py12306/user/job.py index 9ee5496..cb48731 100644 --- a/py12306/user/job.py +++ b/py12306/user/job.py @@ -1,4 +1,6 @@ +import json import pickle +import re from os import path from py12306.config import * @@ -7,6 +9,7 @@ from py12306.helpers.app import * from py12306.helpers.auth_code import AuthCode from py12306.helpers.func import * from py12306.helpers.request import Request +from py12306.log.order_log import OrderLog from py12306.log.user_log import UserLog @@ -23,6 +26,11 @@ class UserJob: passengers = [] retry_time = 5 + # Init page + global_repeat_submit_token = None + ticket_info_for_passenger_form = None + order_request_dto = None + def __init__(self, info, user): self.session = Request() self.heartbeat = user.heartbeat @@ -229,9 +237,35 @@ class UserJob: new_member = { 'name': passenger.get('passenger_name'), 'id_card': passenger.get('passenger_id_no'), + 'id_card_type': passenger.get('passenger_id_type_code'), + 'mobile': passenger.get('mobile_no'), 'type': passenger.get('passenger_type'), 'type_text': dict_find_key_by_value(UserType.dicts, int(passenger.get('passenger_type'))) } results.append(new_member) return results + + def request_init_dc_page(self): + """ + 请求下单页面 拿到 token + :return: + """ + data = {'_json_att': ''} + response = self.session.post(API_INITDC_URL, data) + html = response.text + token = re.search(r'var globalRepeatSubmitToken = \'(.+?)\'', html) + form = re.search(r'var ticketInfoForPassengerForm *= *(\{.+\})', html) + order = re.search(r'var orderRequestDTO *= *(\{.+\})', html) + # 系统忙,请稍后重试 + if html.find('系统忙,请稍后重试') != -1: + OrderLog.add_quick_log(OrderLog.MESSAGE_REQUEST_INIT_DC_PAGE_FAIL).flush() # 重试无用,直接跳过 + return False + try: + self.global_repeat_submit_token = token.groups()[0] + self.ticket_info_for_passenger_form = json.loads(form.groups()[0].replace("'", '"')) + self.order_request_dto = json.loads(order.groups()[0].replace("'", '"')) + except: + pass # TODO Error + + return True diff --git a/py12306/user/user.py b/py12306/user/user.py index 7c13119..4488e0a 100644 --- a/py12306/user/user.py +++ b/py12306/user/user.py @@ -9,6 +9,8 @@ class User: heartbeat = 60 * 2 users = [] + retry_time = 3 + def __init__(self): self.interval = config.USER_HEARTBEAT_INTERVAL @@ -32,7 +34,15 @@ class User: self.users.append(user) @classmethod - def check_members(cls, members, user_key, call_back): + def get_user(cls, key): + self = cls() + for user in self.users: + if user.key == key: + return user + return None + + @classmethod + def check_members(cls, members, key, call_back): """ 检测乘客信息 :param passengers: @@ -42,7 +52,10 @@ class User: for user in self.users: assert isinstance(user, UserJob) - if user.key == user_key and user.check_is_ready(): + if user.key == key and user.check_is_ready(): passengers = user.get_passengers_by_members(members) - call_back(passengers) - pass + return call_back(passengers) + + UserLog.add_quick_log(UserLog.MESSAGE_WAIT_USER_INIT_COMPLETE.format(self.retry_time)).flush() + stay_second(self.retry_time) + return self.check_members(members, key, call_back)