增加乘客检测
This commit is contained in:
7
main.py
7
main.py
@@ -9,9 +9,12 @@ from py12306.user.user import User
|
||||
|
||||
def main():
|
||||
# Thread(target=Query.run).start() # 余票查询
|
||||
create_thread_and_run(User, 'run', wait=False)
|
||||
# Query.run()
|
||||
# create_thread_and_run(User, 'run', wait=False)
|
||||
User.run()
|
||||
Query.run()
|
||||
# Query.run()
|
||||
while True:
|
||||
sleep(1)
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -48,5 +48,19 @@ if path.exists(CONFIG_FILE):
|
||||
exec(open(CONFIG_FILE, encoding='utf8').read())
|
||||
|
||||
|
||||
class UserType:
|
||||
ADULT = 1
|
||||
CHILD = 2
|
||||
STUDENT = 3
|
||||
SOLDIER = 4
|
||||
|
||||
dicts = {
|
||||
'成人': ADULT,
|
||||
'儿童': CHILD,
|
||||
'学生': STUDENT,
|
||||
'残疾军人、伤残人民警察': SOLDIER,
|
||||
}
|
||||
|
||||
|
||||
def get(key, default=None):
|
||||
return eval(key)
|
||||
|
||||
4
py12306/exceptions/MemberInvalidException.py
Executable file
4
py12306/exceptions/MemberInvalidException.py
Executable file
@@ -0,0 +1,4 @@
|
||||
class MemberInvalidException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
0
py12306/exceptions/__init__.py
Normal file
0
py12306/exceptions/__init__.py
Normal file
@@ -42,6 +42,7 @@ API_AUTH_UAMAUTHCLIENT = {
|
||||
API_USER_INFO = {
|
||||
'url': BASE_URL_OF_12306 + '/otn/modifyUser/initQueryUserInfoApi'
|
||||
}
|
||||
API_USER_PASSENGERS = BASE_URL_OF_12306 + '/otn/confirmPassenger/getPassengerDTOs'
|
||||
|
||||
urls = {
|
||||
"auth": { # 登录接口
|
||||
|
||||
@@ -75,15 +75,26 @@ def time_now():
|
||||
return datetime.datetime.now()
|
||||
|
||||
|
||||
def create_thread_and_run(jobs, callback_name, wait=True):
|
||||
def create_thread_and_run(jobs, callback_name, wait=True, daemon=True):
|
||||
threads = []
|
||||
if not isinstance(jobs, list):
|
||||
jobs = [jobs]
|
||||
for job in jobs:
|
||||
thread = threading.Thread(target=getattr(job, callback_name))
|
||||
thread.setDaemon(daemon)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
if wait:
|
||||
for thread in threads: thread.join()
|
||||
|
||||
|
||||
def dict_find_key_by_value(data, value, default=None):
|
||||
result = [k for k, v in data.items() if v == value]
|
||||
return result.pop() if len(result) else default
|
||||
|
||||
|
||||
def array_dict_find_by_key_value(data, key, value, default=None):
|
||||
result = [v for k, v in enumerate(data) if key in v and v[key] == value]
|
||||
return result.pop() if len(result) else default
|
||||
|
||||
# def test:
|
||||
|
||||
@@ -22,7 +22,7 @@ class BaseLog:
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def flush(cls, sep='\n', end='\n', file=None):
|
||||
def flush(cls, sep='\n', end='\n', file=None, exit=False):
|
||||
self = cls()
|
||||
if self.quick_log:
|
||||
logs = self.quick_log
|
||||
@@ -41,6 +41,8 @@ class BaseLog:
|
||||
else:
|
||||
if logs: del self.thread_logs[current_thread_id()]
|
||||
# print(self.logs)
|
||||
if exit:
|
||||
sys.exit()
|
||||
|
||||
@classmethod
|
||||
def add_quick_log(cls, content):
|
||||
|
||||
@@ -14,6 +14,9 @@ class UserLog(BaseLog):
|
||||
MESSAGE_LOADED_USER_BUT_EXPIRED = '用户状态已过期,正在重新登录'
|
||||
MESSAGE_USER_HEARTBEAT_NORMAL = '用户 {} 心跳正常,下次检测 {} 秒后'
|
||||
|
||||
MESSAGE_GET_USER_PASSENGERS_FAIL = '获取用户乘客列表失败,错误原因: {} {} 秒后重试'
|
||||
MESSAGE_USER_PASSENGERS_IS_INVALID = '乘客信息校验失败,在账号 {} 中未找到该乘客: {}'
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.init_data()
|
||||
@@ -45,3 +48,11 @@ class UserLog(BaseLog):
|
||||
self.add_log('正在登录用户 {}'.format(user.user_name))
|
||||
self.flush()
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def print_user_passenger_init_success(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
|
||||
|
||||
34
py12306/order/order.py
Normal file
34
py12306/order/order.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from py12306.helpers.app import *
|
||||
from py12306.helpers.func import *
|
||||
from py12306.log.user_log import UserLog
|
||||
from py12306.user.job import UserJob
|
||||
|
||||
|
||||
class Order:
|
||||
"""
|
||||
处理下单
|
||||
"""
|
||||
heartbeat = 60 * 2
|
||||
users = []
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def run(cls):
|
||||
self = cls()
|
||||
app_available_check()
|
||||
self.start()
|
||||
pass
|
||||
|
||||
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 init_users(self):
|
||||
accounts = config.USER_ACCOUNTS
|
||||
for account in accounts:
|
||||
user = UserJob(info=account, user=self)
|
||||
self.users.append(user)
|
||||
@@ -2,6 +2,8 @@ from py12306.helpers.api import LEFT_TICKETS
|
||||
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.user.user import User
|
||||
|
||||
|
||||
class Job:
|
||||
@@ -15,11 +17,13 @@ class Job:
|
||||
left_station_code = ''
|
||||
arrive_station_code = ''
|
||||
|
||||
account_key = 0
|
||||
allow_seats = []
|
||||
allow_train_numbers = []
|
||||
members = []
|
||||
member_num = 0
|
||||
member_num_take = 0 # 最终提交的人数
|
||||
passengers = []
|
||||
allow_less_member = False
|
||||
|
||||
interval = {}
|
||||
@@ -40,6 +44,7 @@ class Job:
|
||||
self.left_station_code = Station.get_station_key_by_name(self.left_station)
|
||||
self.arrive_station_code = Station.get_station_key_by_name(self.arrive_station)
|
||||
|
||||
self.account_key = info.get('account_key')
|
||||
self.allow_seats = info.get('seats')
|
||||
self.allow_train_numbers = info.get('train_numbers')
|
||||
self.members = info.get('members')
|
||||
@@ -62,6 +67,9 @@ 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:
|
||||
response = self.query_by_date(date)
|
||||
@@ -109,26 +117,29 @@ class Job:
|
||||
if not self.is_has_ticket(ticket_info):
|
||||
continue
|
||||
allow_seats = self.allow_seats if self.allow_seats else list(config.SEAT_TYPES.values()) # 未设置 则所有可用
|
||||
for seat in allow_seats: # 检查座位是否有票
|
||||
ticket_of_seat = ticket_info[get_seat_number_by_name(seat)]
|
||||
if not self.is_has_ticket_by_seat(ticket_of_seat): # 座位是否有效
|
||||
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)]
|
||||
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(),
|
||||
train_number=self.get_info_of_train_number(), seat_type=seat,
|
||||
rest_num=ticket_of_seat)
|
||||
if not self.is_member_number_valid(ticket_of_seat): # 乘车人数是否有效
|
||||
if self.allow_less_member:
|
||||
self.member_num_take = int(ticket_of_seat)
|
||||
QueryLog.print_ticket_num_less_than_specified(ticket_of_seat, self)
|
||||
else:
|
||||
QueryLog.add_quick_log(
|
||||
QueryLog.MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED).flush()
|
||||
continue
|
||||
QueryLog.print_ticket_seat_available(left_date=self.get_info_of_left_date(),
|
||||
train_number=self.get_info_of_train_number(), seat_type=seat,
|
||||
rest_num=ticket_of_seat)
|
||||
if not self.is_member_number_valid(ticket_of_seat): # 乘车人数是否有效
|
||||
if self.allow_less_member:
|
||||
self.member_num_take = int(ticket_of_seat)
|
||||
QueryLog.print_ticket_num_less_than_specified(ticket_of_seat, self)
|
||||
else:
|
||||
QueryLog.add_quick_log(
|
||||
QueryLog.MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED).flush()
|
||||
continue
|
||||
# 检查完成 开始提交订单
|
||||
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('检查完成 开始提交订单')
|
||||
# 检查完成 开始提交订单
|
||||
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('检查完成 开始提交订单')
|
||||
|
||||
def get_results(self, response):
|
||||
"""
|
||||
@@ -164,6 +175,10 @@ class Job:
|
||||
QueryLog.add_stay_log(interval)
|
||||
stay_second(interval)
|
||||
|
||||
def set_passengers(self, passengers):
|
||||
UserLog.print_user_passenger_init_success(passengers)
|
||||
self.passengers = passengers
|
||||
|
||||
# 提供一些便利方法
|
||||
def get_info_of_left_date(self):
|
||||
return self.ticket_info[self.INDEX_LEFT_DATE]
|
||||
|
||||
@@ -31,6 +31,7 @@ class Query:
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
return # DEBUG
|
||||
self.init_jobs()
|
||||
QueryLog.print_init_jobs(jobs=self.jobs)
|
||||
while True:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import pickle
|
||||
from os import path
|
||||
|
||||
from py12306.helpers.api import API_USER_CHECK, API_BASE_LOGIN, API_AUTH_UAMTK, API_AUTH_UAMAUTHCLIENT, API_USER_INFO
|
||||
from py12306.config import *
|
||||
from py12306.helpers.api import *
|
||||
from py12306.helpers.app import *
|
||||
from py12306.helpers.auth_code import AuthCode
|
||||
from py12306.helpers.func import *
|
||||
@@ -18,6 +19,9 @@ class UserJob:
|
||||
user = None
|
||||
info = {} # 用户信息
|
||||
last_heartbeat = None
|
||||
is_ready = False
|
||||
passengers = []
|
||||
retry_time = 5
|
||||
|
||||
def __init__(self, info, user):
|
||||
self.session = Request()
|
||||
@@ -50,6 +54,7 @@ class UserJob:
|
||||
if self.is_first_time() or not self.check_user_is_login():
|
||||
self.handle_login()
|
||||
|
||||
self.is_ready = True
|
||||
UserLog.add_quick_log(UserLog.MESSAGE_USER_HEARTBEAT_NORMAL.format(self.get_name(), self.heartbeat)).flush()
|
||||
self.last_heartbeat = time_now()
|
||||
|
||||
@@ -178,3 +183,55 @@ class UserJob:
|
||||
self.did_loaded_user()
|
||||
return True
|
||||
return None
|
||||
|
||||
def check_is_ready(self):
|
||||
return self.is_ready
|
||||
|
||||
def get_user_passengers(self):
|
||||
if self.passengers: return self.passengers
|
||||
response = self.session.post(API_USER_PASSENGERS)
|
||||
result = response.json()
|
||||
if result.get('data') and result.get('data').get('normal_passengers'):
|
||||
self.passengers = result.get('data').get('normal_passengers')
|
||||
return self.passengers
|
||||
else:
|
||||
UserLog.add_quick_log(
|
||||
UserLog.MESSAGE_GET_USER_PASSENGERS_FAIL.format(result.get('messages', '-'), self.retry_time))
|
||||
stay_second(self.retry_time)
|
||||
return self.get_user_passengers()
|
||||
|
||||
def get_passengers_by_members(self, members):
|
||||
"""
|
||||
获取格式化后的乘客信息
|
||||
:param members:
|
||||
:return:
|
||||
[{
|
||||
name: '项羽',
|
||||
type: 1,
|
||||
id_card: 0000000000000000000,
|
||||
type_text: '成人'
|
||||
}]
|
||||
"""
|
||||
self.get_user_passengers()
|
||||
results = []
|
||||
for member in members:
|
||||
child_check = array_dict_find_by_key_value(results, 'name', member)
|
||||
if child_check:
|
||||
new_member = child_check.copy()
|
||||
new_member['type'] = UserType.CHILD
|
||||
new_member['type_text'] = dict_find_key_by_value(UserType.dicts, int(new_member['type']))
|
||||
else:
|
||||
passenger = array_dict_find_by_key_value(self.passengers, 'passenger_name', member)
|
||||
if not passenger:
|
||||
UserLog.add_quick_log(
|
||||
UserLog.MESSAGE_USER_PASSENGERS_IS_INVALID.format(self.user_name, member)).flush(
|
||||
exit=True) # TODO 需要优化
|
||||
new_member = {
|
||||
'name': passenger.get('passenger_name'),
|
||||
'id_card': passenger.get('passenger_id_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
|
||||
|
||||
@@ -30,3 +30,19 @@ class User:
|
||||
for account in accounts:
|
||||
user = UserJob(info=account, user=self)
|
||||
self.users.append(user)
|
||||
|
||||
@classmethod
|
||||
def check_members(cls, members, user_key, call_back):
|
||||
"""
|
||||
检测乘客信息
|
||||
:param passengers:
|
||||
:return:
|
||||
"""
|
||||
self = cls()
|
||||
|
||||
for user in self.users:
|
||||
assert isinstance(user, UserJob)
|
||||
if user.key == user_key and user.check_is_ready():
|
||||
passengers = user.get_passengers_by_members(members)
|
||||
call_back(passengers)
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user