优化代码,增加测试模式
This commit is contained in:
31
main.py
31
main.py
@@ -1,20 +1,41 @@
|
|||||||
# encoding=utf8
|
# encoding=utf8
|
||||||
import os
|
import sys
|
||||||
from threading import Thread
|
from time import sleep
|
||||||
|
|
||||||
from py12306.helpers.func import *
|
from py12306.helpers.func import *
|
||||||
|
from py12306.helpers.app import *
|
||||||
|
from py12306.log.common_log import CommonLog
|
||||||
from py12306.query.query import Query
|
from py12306.query.query import Query
|
||||||
from py12306.user.user import User
|
from py12306.user.user import User
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Thread(target=Query.run).start() # 余票查询
|
if '--test' in sys.argv or '-t' in sys.argv: test()
|
||||||
# create_thread_and_run(User, 'run', wait=False)
|
CommonLog.print_welcome().print_configs()
|
||||||
|
|
||||||
|
App.run_check()
|
||||||
User.run()
|
User.run()
|
||||||
Query.run()
|
Query.run()
|
||||||
# Query.run()
|
if not Const.IS_TEST:
|
||||||
while True:
|
while True:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
|
CommonLog.test_complete()
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
"""
|
||||||
|
功能检查
|
||||||
|
包含:
|
||||||
|
账号密码验证 (打码)
|
||||||
|
座位验证
|
||||||
|
乘客验证
|
||||||
|
语音验证码验证
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
Const.IS_TEST = True
|
||||||
|
if '--test-notification' in sys.argv or '-n' in sys.argv:
|
||||||
|
Const.IS_TEST_NOTIFICATION = True
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,13 @@ RUNTIME_DIR = PROJECT_DIR + 'runtime/'
|
|||||||
QUERY_DATA_DIR = RUNTIME_DIR + 'query/'
|
QUERY_DATA_DIR = RUNTIME_DIR + 'query/'
|
||||||
USER_DATA_DIR = RUNTIME_DIR + 'user/'
|
USER_DATA_DIR = RUNTIME_DIR + 'user/'
|
||||||
|
|
||||||
STATION_FILE = 'data/stations.txt'
|
STATION_FILE = PROJECT_DIR + 'data/stations.txt'
|
||||||
CONFIG_FILE = 'env.py'
|
CONFIG_FILE = PROJECT_DIR + 'env.py'
|
||||||
|
|
||||||
|
# 语音验证码
|
||||||
|
NOTIFICATION_BY_VOICE_CODE = 0
|
||||||
|
NOTIFICATION_VOICE_CODE_PHONE = ''
|
||||||
|
NOTIFICATION_API_APP_CODE = ''
|
||||||
|
|
||||||
if path.exists(CONFIG_FILE):
|
if path.exists(CONFIG_FILE):
|
||||||
exec(open(CONFIG_FILE, encoding='utf8').read())
|
exec(open(CONFIG_FILE, encoding='utf8').read())
|
||||||
@@ -71,7 +76,3 @@ class UserType:
|
|||||||
'学生': STUDENT,
|
'学生': STUDENT,
|
||||||
'残疾军人、伤残人民警察': SOLDIER,
|
'残疾军人、伤残人民警察': SOLDIER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get(key, default=None):
|
|
||||||
return eval(key)
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
class MemberInvalidException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@@ -50,6 +50,8 @@ API_GET_QUEUE_COUNT = BASE_URL_OF_12306 + '/otn/confirmPassenger/getQueueCount'
|
|||||||
API_CONFIRM_SINGLE_FOR_QUEUE = BASE_URL_OF_12306 + '/otn/confirmPassenger/confirmSingleForQueue'
|
API_CONFIRM_SINGLE_FOR_QUEUE = BASE_URL_OF_12306 + '/otn/confirmPassenger/confirmSingleForQueue'
|
||||||
API_QUERY_ORDER_WAIT_TIME = BASE_URL_OF_12306 + '/otn/confirmPassenger/queryOrderWaitTime?{}' # 排队查询
|
API_QUERY_ORDER_WAIT_TIME = BASE_URL_OF_12306 + '/otn/confirmPassenger/queryOrderWaitTime?{}' # 排队查询
|
||||||
|
|
||||||
|
API_NOTIFICATION_BY_VOICE_CODE = 'http://ali-voice.showapi.com/sendVoice?'
|
||||||
|
|
||||||
urls = {
|
urls = {
|
||||||
"auth": { # 登录接口
|
"auth": { # 登录接口
|
||||||
"req_url": "/passport/web/auth/uamtk",
|
"req_url": "/passport/web/auth/uamtk",
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
from py12306.helpers.func import *
|
from py12306.helpers.func import *
|
||||||
|
from py12306.config import *
|
||||||
|
from py12306.helpers.notification import Notification
|
||||||
from py12306.log.common_log import CommonLog
|
from py12306.log.common_log import CommonLog
|
||||||
|
from py12306.log.order_log import OrderLog
|
||||||
|
|
||||||
|
|
||||||
def app_available_check():
|
def app_available_check():
|
||||||
|
# return True # Debug
|
||||||
now = time_now()
|
now = time_now()
|
||||||
if now.hour >= 23 or now.hour < 6:
|
if now.hour >= 23 or now.hour < 6:
|
||||||
CommonLog.add_quick_log(CommonLog.MESSAGE_12306_IS_CLOSED.format(time_now())).flush()
|
CommonLog.add_quick_log(CommonLog.MESSAGE_12306_IS_CLOSED.format(time_now())).flush()
|
||||||
@@ -11,3 +15,44 @@ def app_available_check():
|
|||||||
open_time += datetime.timedelta(1)
|
open_time += datetime.timedelta(1)
|
||||||
sleep((open_time - now).seconds)
|
sleep((open_time - now).seconds)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class App:
|
||||||
|
"""
|
||||||
|
程序主类
|
||||||
|
TODO 需要完善
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_auto_code(cls):
|
||||||
|
if not config.AUTO_CODE_ACCOUNT.get('user') or not config.AUTO_CODE_ACCOUNT.get('pwd'):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_user_account_is_empty(cls):
|
||||||
|
if config.USER_ACCOUNTS:
|
||||||
|
for account in config.USER_ACCOUNTS:
|
||||||
|
if account:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def test_send_notifications(cls):
|
||||||
|
if config.NOTIFICATION_BY_VOICE_CODE: # 语音通知
|
||||||
|
CommonLog.add_quick_log(CommonLog.MESSAGE_TEST_SEND_VOICE_CODE).flush()
|
||||||
|
Notification.voice_code(config.NOTIFICATION_VOICE_CODE_PHONE, '张三',
|
||||||
|
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format('北京',
|
||||||
|
'深圳'))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run_check(cls):
|
||||||
|
"""
|
||||||
|
待优化
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not cls.check_auto_code():
|
||||||
|
CommonLog.add_quick_log(CommonLog.MESSAGE_CHECK_AUTO_CODE_FAIL).flush(exit=True)
|
||||||
|
if not cls.check_user_account_is_empty():
|
||||||
|
CommonLog.add_quick_log(CommonLog.MESSAGE_CHECK_EMPTY_USER_ACCOUNT).flush(exit=True)
|
||||||
|
if Const.IS_TEST_NOTIFICATION: cls.test_send_notifications()
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import random
|
import random
|
||||||
import threading
|
import threading
|
||||||
|
import functools
|
||||||
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from py12306 import config
|
from py12306 import config
|
||||||
import functools
|
|
||||||
|
|
||||||
|
|
||||||
def singleton(cls):
|
def singleton(cls):
|
||||||
@@ -65,6 +67,15 @@ def stay_second(second, call_back=None):
|
|||||||
return call_back()
|
return call_back()
|
||||||
|
|
||||||
|
|
||||||
|
def sleep_forever():
|
||||||
|
"""
|
||||||
|
当不是主线程时,假象停止
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not is_main_thread():
|
||||||
|
while True: sleep(10000000)
|
||||||
|
|
||||||
|
|
||||||
def is_main_thread():
|
def is_main_thread():
|
||||||
return threading.current_thread() == threading.main_thread()
|
return threading.current_thread() == threading.main_thread()
|
||||||
|
|
||||||
@@ -99,4 +110,17 @@ 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]
|
result = [v for k, v in enumerate(data) if key in v and v[key] == value]
|
||||||
return result.pop() if len(result) else default
|
return result.pop() if len(result) else default
|
||||||
|
|
||||||
# def test:
|
|
||||||
|
def get_true_false_text(value, true='', false=''):
|
||||||
|
if value: return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
def sleep_forever_when_in_test():
|
||||||
|
if Const.IS_TEST: sleep_forever()
|
||||||
|
|
||||||
|
|
||||||
|
@singleton
|
||||||
|
class Const:
|
||||||
|
IS_TEST = False
|
||||||
|
IS_TEST_NOTIFICATION = False
|
||||||
|
|||||||
64
py12306/helpers/notification.py
Normal file
64
py12306/helpers/notification.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import urllib
|
||||||
|
|
||||||
|
from py12306 import config
|
||||||
|
from py12306.helpers.api import *
|
||||||
|
from py12306.helpers.request import Request
|
||||||
|
from py12306.log.common_log import CommonLog
|
||||||
|
|
||||||
|
|
||||||
|
class Notification():
|
||||||
|
"""
|
||||||
|
通知类
|
||||||
|
"""
|
||||||
|
session = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.session = Request()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def voice_code(cls, phone, name='', content=''):
|
||||||
|
self = cls()
|
||||||
|
self.send_voice_code_of_yiyuan(phone, name=name, content=content)
|
||||||
|
|
||||||
|
def send_voice_code_of_yiyuan(self, phone, name='', content=''):
|
||||||
|
"""
|
||||||
|
发送语音验证码
|
||||||
|
购买地址 https://market.aliyun.com/products/57126001/cmapi019902.html?spm=5176.2020520132.101.5.37857218O6iJ3n
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
appcode = config.NOTIFICATION_API_APP_CODE
|
||||||
|
if not appcode:
|
||||||
|
CommonLog.add_quick_log(CommonLog.MESSAGE_EMPTY_APP_CODE).flush()
|
||||||
|
return False
|
||||||
|
body = {
|
||||||
|
'userName': name,
|
||||||
|
'mailNo': content
|
||||||
|
}
|
||||||
|
params = {
|
||||||
|
'content': body,
|
||||||
|
'mobile': phone,
|
||||||
|
'sex': 2,
|
||||||
|
'tNum': 'T170701001056'
|
||||||
|
}
|
||||||
|
response = self.session.request(url=API_NOTIFICATION_BY_VOICE_CODE + urllib.parse.urlencode(params),
|
||||||
|
method='GET', headers={
|
||||||
|
'Authorization': 'APPCODE {}'.format(appcode)
|
||||||
|
})
|
||||||
|
response_message = '-'
|
||||||
|
result = {}
|
||||||
|
try:
|
||||||
|
result = response.json()
|
||||||
|
response_message = result['showapi_res_body']['remark']
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if response.status_code == 401 or response.status_code == 403:
|
||||||
|
return CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_FORBID).flush()
|
||||||
|
if response.status_code == 200 and 'showapi_res_body' in result and result['showapi_res_body'].get('flag'):
|
||||||
|
CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_SEND_SUCCESS.format(response_message)).flush()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_SEND_FAIL.format(response_message)).flush()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Notification.voice_code('13800138000', '张三', '你的车票 广州 到 深圳 购买成功,请登录 12306 进行支付')
|
||||||
@@ -7,7 +7,6 @@ class Station:
|
|||||||
stations = []
|
stations = []
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
print('Station 初始化')
|
|
||||||
if path.exists(config.STATION_FILE):
|
if path.exists(config.STATION_FILE):
|
||||||
result = open(config.STATION_FILE, encoding='utf-8').read()
|
result = open(config.STATION_FILE, encoding='utf-8').read()
|
||||||
result = result.lstrip('@').split('@')
|
result = result.lstrip('@').split('@')
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ import sys
|
|||||||
|
|
||||||
from py12306.helpers.func import *
|
from py12306.helpers.func import *
|
||||||
|
|
||||||
|
|
||||||
class BaseLog:
|
class BaseLog:
|
||||||
logs = []
|
logs = []
|
||||||
thread_logs = {}
|
thread_logs = {}
|
||||||
quick_log = []
|
quick_log = []
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_log(cls, content):
|
def add_log(cls, content=''):
|
||||||
self = cls()
|
self = cls()
|
||||||
# print('添加 Log 主进程{} 进程ID{}'.format(is_main_thread(), current_thread_id()))
|
# print('添加 Log 主进程{} 进程ID{}'.format(is_main_thread(), current_thread_id()))
|
||||||
if is_main_thread():
|
if is_main_thread():
|
||||||
@@ -31,7 +30,6 @@ class BaseLog:
|
|||||||
logs = self.logs
|
logs = self.logs
|
||||||
else:
|
else:
|
||||||
logs = self.thread_logs.get(current_thread_id())
|
logs = self.thread_logs.get(current_thread_id())
|
||||||
# for i in logs:
|
|
||||||
print(*logs, sep=sep, end=end, file=file)
|
print(*logs, sep=sep, end=end, file=file)
|
||||||
if self.quick_log:
|
if self.quick_log:
|
||||||
self.quick_log = []
|
self.quick_log = []
|
||||||
@@ -40,12 +38,11 @@ class BaseLog:
|
|||||||
self.logs = []
|
self.logs = []
|
||||||
else:
|
else:
|
||||||
if logs: del self.thread_logs[current_thread_id()]
|
if logs: del self.thread_logs[current_thread_id()]
|
||||||
# print(self.logs)
|
|
||||||
if exit:
|
if exit:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_quick_log(cls, content):
|
def add_quick_log(cls, content = ''):
|
||||||
self = cls()
|
self = cls()
|
||||||
self.quick_log.append(content)
|
self.quick_log.append(content)
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -1,18 +1,67 @@
|
|||||||
from py12306.log.base import BaseLog
|
from py12306.log.base import BaseLog
|
||||||
|
from py12306.config import *
|
||||||
from py12306.helpers.func import *
|
from py12306.helpers.func import *
|
||||||
|
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class CommonLog(BaseLog):
|
class CommonLog(BaseLog):
|
||||||
|
# 这里如果不声明,会出现重复打印,目前不知道什么原因
|
||||||
|
logs = []
|
||||||
|
thread_logs = {}
|
||||||
|
quick_log = []
|
||||||
|
|
||||||
MESSAGE_12306_IS_CLOSED = '当前时间: {} | 12306 休息时间,程序将在明天早上 6 点自动运行'
|
MESSAGE_12306_IS_CLOSED = '当前时间: {} | 12306 休息时间,程序将在明天早上 6 点自动运行'
|
||||||
MESSAGE_RETRY_AUTH_CODE = '{} 秒后重新获取验证码'
|
MESSAGE_RETRY_AUTH_CODE = '{} 秒后重新获取验证码'
|
||||||
|
|
||||||
|
MESSAGE_EMPTY_APP_CODE = '无法发送语音消息,未填写验证码接口 appcode'
|
||||||
|
MESSAGE_VOICE_API_FORBID = '语音消息发送失败,请检查 appcode 是否填写正确或 套餐余额是否充足'
|
||||||
|
MESSAGE_VOICE_API_SEND_FAIL = '语音消息发送失败,错误原因 {}'
|
||||||
|
MESSAGE_VOICE_API_SEND_SUCCESS = '语音消息发送成功! 接口返回信息 {} '
|
||||||
|
|
||||||
|
MESSAGE_CHECK_AUTO_CODE_FAIL = '请配置打码账号的账号密码'
|
||||||
|
MESSAGE_CHECK_EMPTY_USER_ACCOUNT = '请配置 12306 账号密码'
|
||||||
|
|
||||||
|
MESSAGE_TEST_SEND_VOICE_CODE = '正在测试发送语音验证码...'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.init_data()
|
self.init_data()
|
||||||
|
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
print('Common Log 初始化')
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_welcome(cls):
|
||||||
|
self = cls()
|
||||||
|
self.add_quick_log('######## py12306 购票助手,本程序为开源工具,请勿用于商业用途 ########')
|
||||||
|
if Const.IS_TEST:
|
||||||
|
self.add_quick_log()
|
||||||
|
self.add_quick_log('当前为测试模式,程序运行完成后自动结束')
|
||||||
|
self.add_quick_log()
|
||||||
|
self.flush()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_configs(cls):
|
||||||
|
# 打印配置
|
||||||
|
self = cls()
|
||||||
|
enable = '已开启'
|
||||||
|
disable = '未开启'
|
||||||
|
self.add_quick_log('**** 当前配置 ****')
|
||||||
|
self.add_quick_log('多线程查询: {}'.format(get_true_false_text(config.QUERY_JOB_THREAD_ENABLED, enable, disable)))
|
||||||
|
self.add_quick_log('语音验证码: {}'.format(get_true_false_text(config.QUERY_JOB_THREAD_ENABLED, enable, disable)))
|
||||||
|
self.add_quick_log('查询间隔: {} 秒'.format(config.QUERY_INTERVAL))
|
||||||
|
self.add_quick_log('用户心跳检测间隔: {} 秒'.format(config.USER_HEARTBEAT_INTERVAL))
|
||||||
|
self.add_quick_log()
|
||||||
|
self.flush()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def test_complete(cls):
|
||||||
|
self = cls()
|
||||||
|
self.add_quick_log('# 测试完成,请检查输出是否正确 #')
|
||||||
|
self.flush()
|
||||||
|
return self
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def print_auto_code_fail(cls, reason):
|
def print_auto_code_fail(cls, reason):
|
||||||
|
|||||||
@@ -4,11 +4,17 @@ from py12306.helpers.func import *
|
|||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class OrderLog(BaseLog):
|
class OrderLog(BaseLog):
|
||||||
|
# 这里如果不声明,会出现重复打印,目前不知道什么原因
|
||||||
|
logs = []
|
||||||
|
thread_logs = {}
|
||||||
|
quick_log = []
|
||||||
|
|
||||||
|
|
||||||
MESSAGE_REQUEST_INIT_DC_PAGE_FAIL = '请求初始化订单页面失败'
|
MESSAGE_REQUEST_INIT_DC_PAGE_FAIL = '请求初始化订单页面失败'
|
||||||
|
|
||||||
MESSAGE_SUBMIT_ORDER_REQUEST_FAIL = '提交订单失败,错误原因 {}'
|
MESSAGE_SUBMIT_ORDER_REQUEST_FAIL = '提交订单失败,错误原因 {} \n'
|
||||||
MESSAGE_SUBMIT_ORDER_REQUEST_SUCCESS = '提交订单成功'
|
MESSAGE_SUBMIT_ORDER_REQUEST_SUCCESS = '提交订单成功'
|
||||||
MESSAGE_CHECK_ORDER_INFO_FAIL = '检查订单失败,错误原因 {}'
|
MESSAGE_CHECK_ORDER_INFO_FAIL = '检查订单失败,错误原因 {} \n'
|
||||||
MESSAGE_CHECK_ORDER_INFO_SUCCESS = '检查订单成功'
|
MESSAGE_CHECK_ORDER_INFO_SUCCESS = '检查订单成功'
|
||||||
|
|
||||||
MESSAGE_GET_QUEUE_COUNT_SUCCESS = '排队成功,你当前排在第 {} 位, 余票还剩余 {} 张'
|
MESSAGE_GET_QUEUE_COUNT_SUCCESS = '排队成功,你当前排在第 {} 位, 余票还剩余 {} 张'
|
||||||
@@ -25,6 +31,10 @@ class OrderLog(BaseLog):
|
|||||||
MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE = '车票购买成功!'
|
MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE = '车票购买成功!'
|
||||||
MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT = '请及时器登录12306,打开 \'未完成订单\',在30分钟内完成支付!'
|
MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT = '请及时器登录12306,打开 \'未完成订单\',在30分钟内完成支付!'
|
||||||
|
|
||||||
|
MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND = '正在发送语音通知, 第 {} 次'
|
||||||
|
MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT = '你的车票 {} 到 {} 购买成功,请登录 12306 进行支付'
|
||||||
|
|
||||||
|
MESSAGE_JOB_CLOSED = '当前任务已结束'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def print_passenger_did_deleted(cls, passengers):
|
def print_passenger_did_deleted(cls, passengers):
|
||||||
@@ -37,6 +47,6 @@ class OrderLog(BaseLog):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def print_ticket_did_ordered(cls, order_id):
|
def print_ticket_did_ordered(cls, order_id):
|
||||||
self = cls()
|
self = cls()
|
||||||
self.add_quick_log('# 车票购买成功,订单号{} #'.format(order_id))
|
self.add_quick_log('# 车票购买成功,订单号 {} #'.format(order_id))
|
||||||
self.flush()
|
self.flush()
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ from py12306.helpers.func import *
|
|||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class QueryLog(BaseLog):
|
class QueryLog(BaseLog):
|
||||||
|
# 这里如果不声明,会出现重复打印,目前不知道什么原因
|
||||||
|
logs = []
|
||||||
|
thread_logs = {}
|
||||||
|
quick_log = []
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'query_count': 1,
|
'query_count': 1,
|
||||||
'last_time': '',
|
'last_time': '',
|
||||||
@@ -27,9 +32,10 @@ class QueryLog(BaseLog):
|
|||||||
|
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
# 获取上次记录
|
# 获取上次记录
|
||||||
print('Query Log 初始化')
|
if Const.IS_TEST: return
|
||||||
if path.exists(self.data_path):
|
if path.exists(self.data_path):
|
||||||
result = open(self.data_path, encoding='utf-8').read()
|
with open(self.data_path, encoding='utf-8') as f:
|
||||||
|
result = f.read()
|
||||||
if result:
|
if result:
|
||||||
result = json.loads(result)
|
result = json.loads(result)
|
||||||
self.data = {**self.data, **result}
|
self.data = {**self.data, **result}
|
||||||
@@ -50,10 +56,11 @@ class QueryLog(BaseLog):
|
|||||||
self.add_log('乘车日期:{}'.format(job.left_dates))
|
self.add_log('乘车日期:{}'.format(job.left_dates))
|
||||||
self.add_log('坐席:{}'.format(','.join(job.allow_seats)))
|
self.add_log('坐席:{}'.format(','.join(job.allow_seats)))
|
||||||
self.add_log('乘车人:{}'.format(','.join(job.members)))
|
self.add_log('乘车人:{}'.format(','.join(job.members)))
|
||||||
self.add_log('筛选车次:{}'.format(','.join(job.allow_train_numbers)))
|
self.add_log('筛选车次:{}'.format(','.join(job.allow_train_numbers if job.allow_train_numbers else ['不筛选'])))
|
||||||
# 乘车日期:['2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27']
|
# 乘车日期:['2019-01-24', '2019-01-25', '2019-01-26', '2019-01-27']
|
||||||
index += 1
|
|
||||||
self.add_log('')
|
self.add_log('')
|
||||||
|
index += 1
|
||||||
|
|
||||||
self.flush()
|
self.flush()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -71,7 +78,8 @@ class QueryLog(BaseLog):
|
|||||||
def print_ticket_seat_available(cls, left_date, train_number, seat_type, rest_num):
|
def print_ticket_seat_available(cls, left_date, train_number, seat_type, rest_num):
|
||||||
self = cls()
|
self = cls()
|
||||||
self.add_quick_log(
|
self.add_quick_log(
|
||||||
'查询到座位可用 出发时间 {left_date} 车次 {train_number} 座位类型 {seat_type} 余票数量 {rest_num}'.format(left_date=left_date,
|
'[ 查询到座位可用 出发时间 {left_date} 车次 {train_number} 座位类型 {seat_type} 余票数量 {rest_num} ]'.format(
|
||||||
|
left_date=left_date,
|
||||||
train_number=train_number,
|
train_number=train_number,
|
||||||
seat_type=seat_type,
|
seat_type=seat_type,
|
||||||
rest_num=rest_num))
|
rest_num=rest_num))
|
||||||
@@ -107,8 +115,6 @@ class QueryLog(BaseLog):
|
|||||||
self.refresh_data()
|
self.refresh_data()
|
||||||
if is_main_thread():
|
if is_main_thread():
|
||||||
self.flush()
|
self.flush()
|
||||||
else:
|
|
||||||
self.add_log('\n')
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -121,7 +127,7 @@ class QueryLog(BaseLog):
|
|||||||
self.add_quick_log('============================================================')
|
self.add_quick_log('============================================================')
|
||||||
self.add_quick_log('|=== 查询记录恢复成功 上次查询 {last_date} ===|'.format(last_date=self.data.get('last_time')))
|
self.add_quick_log('|=== 查询记录恢复成功 上次查询 {last_date} ===|'.format(last_date=self.data.get('last_time')))
|
||||||
self.add_quick_log('============================================================')
|
self.add_quick_log('============================================================')
|
||||||
self.add_log('')
|
self.add_quick_log('')
|
||||||
self.flush()
|
self.flush()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ from py12306.helpers.func import *
|
|||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class UserLog(BaseLog):
|
class UserLog(BaseLog):
|
||||||
|
# 这里如果不声明,会出现重复打印,目前不知道什么原因
|
||||||
|
logs = []
|
||||||
|
thread_logs = {}
|
||||||
|
quick_log = []
|
||||||
|
|
||||||
MESSAGE_DOWNLAOD_AUTH_CODE_FAIL = '验证码下载失败 错误原因: {} {} 秒后重试'
|
MESSAGE_DOWNLAOD_AUTH_CODE_FAIL = '验证码下载失败 错误原因: {} {} 秒后重试'
|
||||||
MESSAGE_DOWNLAODING_THE_CODE = '正在下载验证码...'
|
MESSAGE_DOWNLAODING_THE_CODE = '正在下载验证码...'
|
||||||
MESSAGE_CODE_AUTH_FAIL = '验证码验证失败 错误原因: {} {} 秒后重试'
|
MESSAGE_CODE_AUTH_FAIL = '验证码验证失败 错误原因: {} {} 秒后重试'
|
||||||
@@ -17,14 +22,14 @@ class UserLog(BaseLog):
|
|||||||
MESSAGE_GET_USER_PASSENGERS_FAIL = '获取用户乘客列表失败,错误原因: {} {} 秒后重试'
|
MESSAGE_GET_USER_PASSENGERS_FAIL = '获取用户乘客列表失败,错误原因: {} {} 秒后重试'
|
||||||
MESSAGE_USER_PASSENGERS_IS_INVALID = '乘客信息校验失败,在账号 {} 中未找到该乘客: {}'
|
MESSAGE_USER_PASSENGERS_IS_INVALID = '乘客信息校验失败,在账号 {} 中未找到该乘客: {}'
|
||||||
|
|
||||||
MESSAGE_WAIT_USER_INIT_COMPLETE = '未找到可用账号或用户正在初始化,{} 秒重试'
|
MESSAGE_WAIT_USER_INIT_COMPLETE = '未找到可用账号或用户正在初始化,{} 秒后重试'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.init_data()
|
self.init_data()
|
||||||
|
|
||||||
def init_data(self):
|
def init_data(self):
|
||||||
print('User Log 初始化')
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def print_init_users(cls, users):
|
def print_init_users(cls, users):
|
||||||
@@ -33,7 +38,7 @@ class UserLog(BaseLog):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self = cls()
|
self = cls()
|
||||||
self.add_log('================== 发现 {} 个用户 =================='.format(len(users)))
|
self.add_log('# 发现 {} 个用户 #'.format(len(users)))
|
||||||
self.flush()
|
self.flush()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from py12306.config import UserType
|
|||||||
from py12306.helpers.api import *
|
from py12306.helpers.api import *
|
||||||
from py12306.helpers.app import *
|
from py12306.helpers.app import *
|
||||||
from py12306.helpers.func import *
|
from py12306.helpers.func import *
|
||||||
|
from py12306.helpers.notification import Notification
|
||||||
from py12306.log.order_log import OrderLog
|
from py12306.log.order_log import OrderLog
|
||||||
from py12306.log.user_log import UserLog
|
from py12306.log.user_log import UserLog
|
||||||
|
|
||||||
@@ -31,6 +32,11 @@ class Order:
|
|||||||
retry_time = 3
|
retry_time = 3
|
||||||
wait_queue_interval = 3
|
wait_queue_interval = 3
|
||||||
|
|
||||||
|
order_id = 0
|
||||||
|
|
||||||
|
notification_sustain_time = 60 * 30 # 通知持续时间 30 分钟
|
||||||
|
notification_interval = 5 * 60 # 通知间隔
|
||||||
|
|
||||||
def __init__(self, query, user):
|
def __init__(self, query, user):
|
||||||
self.session = user.session
|
self.session = user.session
|
||||||
# assert isinstance(query, Job) # 循环引用
|
# assert isinstance(query, Job) # 循环引用
|
||||||
@@ -57,9 +63,31 @@ class Order:
|
|||||||
if not self.confirm_single_for_queue(): return
|
if not self.confirm_single_for_queue(): return
|
||||||
order_id = self.query_order_wait_time()
|
order_id = self.query_order_wait_time()
|
||||||
if order_id: # 发送通知
|
if order_id: # 发送通知
|
||||||
OrderLog.print_ticket_did_ordered(order_id)
|
self.order_id = order_id
|
||||||
|
self.order_did_success()
|
||||||
|
|
||||||
|
def order_did_success(self):
|
||||||
|
OrderLog.print_ticket_did_ordered(self.order_id)
|
||||||
OrderLog.notification(OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE,
|
OrderLog.notification(OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE,
|
||||||
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT)
|
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT)
|
||||||
|
self.send_notification()
|
||||||
|
|
||||||
|
def send_notification(self):
|
||||||
|
num = 0 # 通知次数
|
||||||
|
sustain_time = self.notification_sustain_time
|
||||||
|
while sustain_time: # TODO 后面直接查询有没有待支付的订单就可以
|
||||||
|
num += 1
|
||||||
|
if config.NOTIFICATION_BY_VOICE_CODE: # 语音通知
|
||||||
|
OrderLog.add_quick_log(OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND.format(num))
|
||||||
|
Notification.voice_code(config.NOTIFICATION_VOICE_CODE_PHONE, self.user_ins.get_name(),
|
||||||
|
OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format(
|
||||||
|
self.query_ins.left_station, self.query_ins.arrive_station))
|
||||||
|
sustain_time -= self.notification_interval
|
||||||
|
sleep(self.notification_interval)
|
||||||
|
|
||||||
|
OrderLog.add_quick_log(OrderLog.MESSAGE_JOB_CLOSED)
|
||||||
|
# 结束运行
|
||||||
|
while True: sleep(self.retry_time)
|
||||||
|
|
||||||
def submit_order_request(self):
|
def submit_order_request(self):
|
||||||
data = {
|
data = {
|
||||||
@@ -277,9 +305,11 @@ class Order:
|
|||||||
elif result_data.get('waitTime') and result_data.get('waitTime') >= 0:
|
elif result_data.get('waitTime') and result_data.get('waitTime') >= 0:
|
||||||
OrderLog.add_quick_log(
|
OrderLog.add_quick_log(
|
||||||
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING.format(result_data.get('waitTime'))).flush()
|
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_WAITING.format(result_data.get('waitTime'))).flush()
|
||||||
elif result_data.get('msg'): # 失败
|
elif result_data.get('msg'): # 失败 对不起,由于您取消次数过多,今日将不能继续受理您的订票请求。1月8日您可继续使用订票功能。
|
||||||
|
# TODO 需要增加判断 直接结束
|
||||||
OrderLog.add_quick_log(
|
OrderLog.add_quick_log(
|
||||||
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL.format(result_data.get('msg', '-'))).flush()
|
OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL.format(result_data.get('msg', '-'))).flush()
|
||||||
|
stay_second(self.retry_time)
|
||||||
return False
|
return False
|
||||||
elif result.get('messages') or result.get('validateMessages'):
|
elif result.get('messages') or result.get('validateMessages'):
|
||||||
OrderLog.add_quick_log(OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL.format(
|
OrderLog.add_quick_log(OrderLog.MESSAGE_QUERY_ORDER_WAIT_TIME_FAIL.format(
|
||||||
|
|||||||
@@ -80,20 +80,21 @@ class Job:
|
|||||||
self.handle_response(response)
|
self.handle_response(response)
|
||||||
self.safe_stay()
|
self.safe_stay()
|
||||||
if is_main_thread():
|
if is_main_thread():
|
||||||
QueryLog.flush(sep='\t')
|
QueryLog.flush(sep='\t\t')
|
||||||
else:
|
|
||||||
QueryLog.add_log('\n')
|
|
||||||
if is_main_thread():
|
if is_main_thread():
|
||||||
QueryLog.add_quick_log('').flush()
|
QueryLog.add_quick_log('').flush()
|
||||||
else:
|
else:
|
||||||
QueryLog.flush(sep='\t')
|
QueryLog.add_log('\n').flush(sep='\t\t')
|
||||||
|
|
||||||
def query_by_date(self, date):
|
def query_by_date(self, date):
|
||||||
"""
|
"""
|
||||||
通过日期进行查询
|
通过日期进行查询
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
QueryLog.add_log(QueryLog.MESSAGE_QUERY_START_BY_DATE.format(date, self.left_station, self.arrive_station))
|
QueryLog.add_log(
|
||||||
|
('\n' if not is_main_thread() else '') + QueryLog.MESSAGE_QUERY_START_BY_DATE.format(date,
|
||||||
|
self.left_station,
|
||||||
|
self.arrive_station))
|
||||||
url = LEFT_TICKETS.get('url').format(left_date=date, left_station=self.left_station_code,
|
url = LEFT_TICKETS.get('url').format(left_date=date, left_station=self.left_station_code,
|
||||||
arrive_station=self.arrive_station_code, type='leftTicket/queryZ')
|
arrive_station=self.arrive_station_code, type='leftTicket/queryZ')
|
||||||
|
|
||||||
@@ -141,6 +142,7 @@ class Job:
|
|||||||
QueryLog.add_quick_log(
|
QueryLog.add_quick_log(
|
||||||
QueryLog.MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED).flush()
|
QueryLog.MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED).flush()
|
||||||
continue
|
continue
|
||||||
|
if Const.IS_TEST: return
|
||||||
# 检查完成 开始提交订单
|
# 检查完成 开始提交订单
|
||||||
QueryLog.print_ticket_available(left_date=self.get_info_of_left_date(),
|
QueryLog.print_ticket_available(left_date=self.get_info_of_left_date(),
|
||||||
train_number=self.get_info_of_train_number(),
|
train_number=self.get_info_of_train_number(),
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ class Query:
|
|||||||
# return # DEBUG
|
# return # DEBUG
|
||||||
self.init_jobs()
|
self.init_jobs()
|
||||||
QueryLog.print_init_jobs(jobs=self.jobs)
|
QueryLog.print_init_jobs(jobs=self.jobs)
|
||||||
|
stay_second(1)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
app_available_check()
|
app_available_check()
|
||||||
if config.QUERY_JOB_THREAD_ENABLED: # 多线程
|
if config.QUERY_JOB_THREAD_ENABLED: # 多线程
|
||||||
@@ -41,6 +43,7 @@ class Query:
|
|||||||
else:
|
else:
|
||||||
for job in self.jobs:
|
for job in self.jobs:
|
||||||
job.run()
|
job.run()
|
||||||
|
if Const.IS_TEST: return
|
||||||
|
|
||||||
def init_jobs(self):
|
def init_jobs(self):
|
||||||
jobs = config.QUERY_JOBS
|
jobs = config.QUERY_JOBS
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class UserJob:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# load user
|
# load user
|
||||||
|
if not Const.IS_TEST:
|
||||||
self.load_user()
|
self.load_user()
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ class UserJob:
|
|||||||
while True:
|
while True:
|
||||||
app_available_check()
|
app_available_check()
|
||||||
self.check_heartbeat()
|
self.check_heartbeat()
|
||||||
|
if Const.IS_TEST: return
|
||||||
sleep(self.heartbeat_interval)
|
sleep(self.heartbeat_interval)
|
||||||
|
|
||||||
def check_heartbeat(self):
|
def check_heartbeat(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user