Commit 27a5a13c authored by Jalin's avatar Jalin

完成自动下单

parent 0e287096
......@@ -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
......
......@@ -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": { # 登录接口
......
......@@ -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():
......
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
......@@ -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
......
......@@ -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()
......
This diff is collapsed.
......@@ -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]
......@@ -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:
......
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
......@@ -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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment