增加用户功能
This commit is contained in:
6
main.py
6
main.py
@@ -4,12 +4,14 @@ from threading import Thread
|
|||||||
|
|
||||||
from py12306.log.query_log import QueryLog
|
from py12306.log.query_log import QueryLog
|
||||||
from py12306.query.query import Query
|
from py12306.query.query import Query
|
||||||
|
from py12306.user.user import User
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Thread(target=Query.run).start() # 余票查询
|
# Thread(target=Query.run).start() # 余票查询
|
||||||
QueryLog.add_log('init')
|
# QueryLog.add_log('init')
|
||||||
Query.run()
|
# Query.run()
|
||||||
|
User.run()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ USER_HEARTBEAT_INTERVAL = 120
|
|||||||
# 多线程查询
|
# 多线程查询
|
||||||
QUERY_JOB_THREAD_ENABLED = 0
|
QUERY_JOB_THREAD_ENABLED = 0
|
||||||
|
|
||||||
|
# 打码平台账号
|
||||||
|
AUTO_CODE_ACCOUNT = {
|
||||||
|
'user': '',
|
||||||
|
'pwd': ''
|
||||||
|
}
|
||||||
|
|
||||||
SEAT_TYPES = {
|
SEAT_TYPES = {
|
||||||
'商务座': 32,
|
'商务座': 32,
|
||||||
'一等座': 31,
|
'一等座': 31,
|
||||||
@@ -28,10 +34,12 @@ SEAT_TYPES = {
|
|||||||
'无座': 26,
|
'无座': 26,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Query
|
PROJECT_DIR = path.dirname(path.dirname(path.abspath(__file__))) + '/'
|
||||||
QUERY_DATA_DIR = 'runtime/query'
|
|
||||||
USER_DATA_DIR = 'runtime/user'
|
|
||||||
|
|
||||||
|
# Query
|
||||||
|
RUNTIME_DIR = PROJECT_DIR + 'runtime/'
|
||||||
|
QUERY_DATA_DIR = RUNTIME_DIR + 'query/'
|
||||||
|
USER_DATA_DIR = RUNTIME_DIR + 'user/'
|
||||||
|
|
||||||
STATION_FILE = 'data/stations.txt'
|
STATION_FILE = 'data/stations.txt'
|
||||||
CONFIG_FILE = 'env.py'
|
CONFIG_FILE = 'env.py'
|
||||||
|
|||||||
71
py12306/helpers/OCR.py
Normal file
71
py12306/helpers/OCR.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
from py12306 import config
|
||||||
|
from py12306.log.common_log import CommonLog
|
||||||
|
from py12306.vender.ruokuai.main import RKClient
|
||||||
|
|
||||||
|
|
||||||
|
class OCR:
|
||||||
|
"""
|
||||||
|
图片识别
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_img_position(cls, img_path):
|
||||||
|
"""
|
||||||
|
获取图像坐标
|
||||||
|
:param img_path:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self = cls()
|
||||||
|
return self.get_img_position_by_ruokuai(img_path)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_img_position_by_ruokuai(self, img_path):
|
||||||
|
ruokuai_account = config.AUTO_CODE_ACCOUNT
|
||||||
|
soft_id = '119671'
|
||||||
|
soft_key = '6839cbaca1f942f58d2760baba5ed987'
|
||||||
|
rc = RKClient(ruokuai_account.get('user'), ruokuai_account.get('pwd'), soft_id, soft_key)
|
||||||
|
im = open(img_path, 'rb').read()
|
||||||
|
result = rc.rk_create(im, 6113)
|
||||||
|
if "Result" in result:
|
||||||
|
return self.get_image_position_by_offset(list(result['Result']))
|
||||||
|
CommonLog.print_auto_code_fail(result.get("Error", '-'))
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_image_position_by_offset(self, offsets):
|
||||||
|
positions = []
|
||||||
|
for offset in offsets:
|
||||||
|
if offset == '1':
|
||||||
|
y = 46
|
||||||
|
x = 42
|
||||||
|
elif offset == '2':
|
||||||
|
y = 46
|
||||||
|
x = 105
|
||||||
|
elif offset == '3':
|
||||||
|
y = 45
|
||||||
|
x = 184
|
||||||
|
elif offset == '4':
|
||||||
|
y = 48
|
||||||
|
x = 256
|
||||||
|
elif offset == '5':
|
||||||
|
y = 36
|
||||||
|
x = 117
|
||||||
|
elif offset == '6':
|
||||||
|
y = 112
|
||||||
|
x = 115
|
||||||
|
elif offset == '7':
|
||||||
|
y = 114
|
||||||
|
x = 181
|
||||||
|
elif offset == '8':
|
||||||
|
y = 111
|
||||||
|
x = 252
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
positions.append(x)
|
||||||
|
positions.append(y)
|
||||||
|
return positions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pass
|
||||||
|
# code_result = AuthCode.get_auth_code()
|
||||||
@@ -26,8 +26,22 @@ API_USER_CHECK = {
|
|||||||
"is_cdn": True,
|
"is_cdn": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
API_AUTH_CODE_DOWNLOAD = {
|
||||||
|
'url': BASE_URL_OF_12306 + '/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&_={random}'
|
||||||
|
}
|
||||||
|
API_AUTH_CODE_CHECK = {
|
||||||
|
'url': BASE_URL_OF_12306 + '/passport/captcha/captcha-check?answer={answer}&rand=sjrand&login_site=E&_={random}'
|
||||||
|
}
|
||||||
|
API_AUTH_UAMTK = {
|
||||||
|
'url': BASE_URL_OF_12306 + '/passport/web/auth/uamtk'
|
||||||
|
}
|
||||||
|
API_AUTH_UAMAUTHCLIENT = {
|
||||||
|
'url': BASE_URL_OF_12306 + '/otn/uamauthclient'
|
||||||
|
}
|
||||||
|
|
||||||
|
API_USER_INFO = {
|
||||||
|
'url': BASE_URL_OF_12306 + '/otn/modifyUser/initQueryUserInfoApi'
|
||||||
|
}
|
||||||
|
|
||||||
urls = {
|
urls = {
|
||||||
"auth": { # 登录接口
|
"auth": { # 登录接口
|
||||||
|
|||||||
69
py12306/helpers/auth_code.py
Normal file
69
py12306/helpers/auth_code.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
|
from requests.exceptions import SSLError
|
||||||
|
|
||||||
|
from py12306.helpers.OCR import OCR
|
||||||
|
from py12306.helpers.api import API_AUTH_CODE_DOWNLOAD, API_AUTH_CODE_CHECK
|
||||||
|
from py12306.helpers.request import Request
|
||||||
|
from py12306.helpers.func import *
|
||||||
|
from py12306.log.common_log import CommonLog
|
||||||
|
from py12306.log.user_log import UserLog
|
||||||
|
|
||||||
|
|
||||||
|
class AuthCode:
|
||||||
|
"""
|
||||||
|
验证码类
|
||||||
|
"""
|
||||||
|
session = None
|
||||||
|
data_path = config.RUNTIME_DIR
|
||||||
|
retry_time = 1
|
||||||
|
|
||||||
|
def __init__(self, session):
|
||||||
|
self.session = session
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_auth_code(cls, session):
|
||||||
|
self = cls(session)
|
||||||
|
img_path = self.download_code()
|
||||||
|
position = OCR.get_img_position(img_path)
|
||||||
|
answer = ','.join(map(str, position))
|
||||||
|
if not self.check_code(answer):
|
||||||
|
time.sleep(self.retry_time)
|
||||||
|
return self.get_auth_code(session)
|
||||||
|
return position
|
||||||
|
|
||||||
|
def download_code(self):
|
||||||
|
url = API_AUTH_CODE_DOWNLOAD.get('url').format(random=random.random())
|
||||||
|
code_path = self.data_path + 'code.png'
|
||||||
|
try:
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_DOWNLAODING_THE_CODE).flush()
|
||||||
|
response = self.session.save_to_file(url, code_path) # TODO 返回错误情况
|
||||||
|
except SSLError as e:
|
||||||
|
UserLog.add_quick_log(
|
||||||
|
UserLog.MESSAGE_DOWNLAOD_AUTH_CODE_FAIL.format(e, self.retry_time)).flush()
|
||||||
|
time.sleep(self.retry_time)
|
||||||
|
return self.download_code()
|
||||||
|
return code_path
|
||||||
|
|
||||||
|
def check_code(self, answer):
|
||||||
|
"""
|
||||||
|
校验验证码
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
url = API_AUTH_CODE_CHECK.get('url').format(answer=answer, random=random.random())
|
||||||
|
response = self.session.get(url)
|
||||||
|
result = response.json()
|
||||||
|
if result.get('result_code') == '4':
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_CODE_AUTH_SUCCESS).flush()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
UserLog.add_quick_log(
|
||||||
|
UserLog.MESSAGE_CODE_AUTH_FAIL.format(result.get('result_message'), self.retry_time)).flush()
|
||||||
|
self.session.cookies.clear_session_cookies()
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
code_result = AuthCode.get_auth_code()
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
import random
|
import random
|
||||||
import threading
|
import threading
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@@ -65,7 +66,11 @@ def stay_second(second):
|
|||||||
def is_main_thread():
|
def is_main_thread():
|
||||||
return threading.current_thread() == threading.main_thread()
|
return threading.current_thread() == threading.main_thread()
|
||||||
|
|
||||||
|
|
||||||
def current_thread_id():
|
def current_thread_id():
|
||||||
return threading.current_thread().ident
|
return threading.current_thread().ident
|
||||||
|
|
||||||
|
|
||||||
|
def time_now():
|
||||||
|
return datetime.datetime.now()
|
||||||
# def test:
|
# def test:
|
||||||
|
|||||||
20
py12306/helpers/request.py
Normal file
20
py12306/helpers/request.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from requests_html import HTMLSession
|
||||||
|
|
||||||
|
|
||||||
|
class Request(HTMLSession):
|
||||||
|
"""
|
||||||
|
请求处理类
|
||||||
|
"""
|
||||||
|
# session = {}
|
||||||
|
|
||||||
|
# def __init__(self, mock_browser=True, session=None):
|
||||||
|
# super().__init__(mock_browser=mock_browser)
|
||||||
|
# self.session = session if session else HTMLSession()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def save_to_file(self, url, path):
|
||||||
|
response = self.get(url, stream=True)
|
||||||
|
with open(path, 'wb') as f:
|
||||||
|
for chunk in response.iter_content(chunk_size=1024):
|
||||||
|
f.write(chunk)
|
||||||
|
return response
|
||||||
20
py12306/log/common_log.py
Normal file
20
py12306/log/common_log.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from py12306.log.base import BaseLog
|
||||||
|
from py12306.helpers.func import *
|
||||||
|
|
||||||
|
|
||||||
|
@singleton
|
||||||
|
class CommonLog(BaseLog):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.init_data()
|
||||||
|
|
||||||
|
def init_data(self):
|
||||||
|
print('Common Log 初始化')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_auto_code_fail(cls, reason):
|
||||||
|
self = cls()
|
||||||
|
self.add_quick_log('打码失败: 错误原因 {reason}'.format(reason=reason))
|
||||||
|
self.flush()
|
||||||
|
return self
|
||||||
@@ -12,7 +12,7 @@ class QueryLog(BaseLog):
|
|||||||
'query_count': 1,
|
'query_count': 1,
|
||||||
'last_time': '',
|
'last_time': '',
|
||||||
}
|
}
|
||||||
data_path = config.QUERY_DATA_DIR + '/status.json'
|
data_path = config.QUERY_DATA_DIR + 'status.json'
|
||||||
|
|
||||||
LOG_INIT_JOBS = ''
|
LOG_INIT_JOBS = ''
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,15 @@ from py12306.helpers.func import *
|
|||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class UserLog(BaseLog):
|
class UserLog(BaseLog):
|
||||||
|
MESSAGE_DOWNLAOD_AUTH_CODE_FAIL = '验证码下载失败 错误原因: {} {} 秒后重试'
|
||||||
|
MESSAGE_DOWNLAODING_THE_CODE = '正在下载验证码...'
|
||||||
|
MESSAGE_CODE_AUTH_FAIL = '验证码验证失败 错误原因: {} {} 秒后重试'
|
||||||
|
MESSAGE_CODE_AUTH_SUCCESS = '验证码验证成功 开始登录...'
|
||||||
|
MESSAGE_LOGIN_FAIL = '登录失败 错误原因: {}'
|
||||||
|
MESSAGE_LOADED_USER = '正在尝试恢复用户: {}'
|
||||||
|
MESSAGE_LOADED_USER_SUCCESS = '用户恢复成功: {}'
|
||||||
|
MESSAGE_LOADED_USER_BUT_EXPIRED = '用户状态已过期,正在重新登录'
|
||||||
|
MESSAGE_USER_HEARTBEAT_NORMAL = '用户 {} 心跳正常,下次检测 {} 秒后'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -20,6 +29,19 @@ class UserLog(BaseLog):
|
|||||||
"""
|
"""
|
||||||
self = cls()
|
self = cls()
|
||||||
self.add_log('================== 发现 {} 个用户 =================='.format(len(users)))
|
self.add_log('================== 发现 {} 个用户 =================='.format(len(users)))
|
||||||
self.add_log('')
|
self.flush()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_welcome_user(cls, user):
|
||||||
|
self = cls()
|
||||||
|
self.add_log('# 欢迎回来,{} #'.format(user.get_name()))
|
||||||
|
self.flush()
|
||||||
|
return self
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def print_start_login(cls, user):
|
||||||
|
self = cls()
|
||||||
|
self.add_log('正在登录用户 {}'.format(user.user_name))
|
||||||
self.flush()
|
self.flush()
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ class Query:
|
|||||||
thread = threading.Thread(target=job.run)
|
thread = threading.Thread(target=job.run)
|
||||||
thread.start()
|
thread.start()
|
||||||
threads.append(thread)
|
threads.append(thread)
|
||||||
for thread in threads:
|
for thread in threads: thread.join()
|
||||||
thread.join()
|
|
||||||
else:
|
else:
|
||||||
for job in self.jobs:
|
for job in self.jobs:
|
||||||
job.run()
|
job.run()
|
||||||
|
|||||||
@@ -1,68 +1,178 @@
|
|||||||
|
import pickle
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
from requests_html import HTMLSession
|
from py12306.helpers.api import API_USER_CHECK, API_BASE_LOGIN, API_AUTH_UAMTK, API_AUTH_UAMAUTHCLIENT, API_USER_INFO
|
||||||
|
from py12306.helpers.auth_code import AuthCode
|
||||||
from py12306.helpers.api import API_USER_CHECK, API_BASE_LOGIN
|
|
||||||
from py12306.helpers.func import *
|
from py12306.helpers.func import *
|
||||||
|
from py12306.helpers.request import Request
|
||||||
|
from py12306.log.user_log import UserLog
|
||||||
|
|
||||||
|
|
||||||
class UserJob:
|
class UserJob:
|
||||||
heartbeat = 60 * 2
|
heartbeat = 60 * 2 # 心跳保持时长
|
||||||
|
heartbeat_interval = 5
|
||||||
key = None
|
key = None
|
||||||
user_name: ''
|
user_name = ''
|
||||||
password: ''
|
password = ''
|
||||||
user: None
|
user = None
|
||||||
|
info = {} # 用户信息
|
||||||
|
last_heartbeat = None
|
||||||
|
|
||||||
def __init__(self, info, user):
|
def __init__(self, info, user):
|
||||||
self.session = HTMLSession()
|
self.session = Request()
|
||||||
# cookie TODO
|
|
||||||
self.heartbeat = user.heartbeat
|
self.heartbeat = user.heartbeat
|
||||||
|
|
||||||
self.key = info.get('key')
|
self.key = info.get('key')
|
||||||
self.user_name = info.get('user_name')
|
self.user_name = info.get('user_name')
|
||||||
self.password = info.get('password')
|
self.password = info.get('password')
|
||||||
self.user = user
|
self.user = user
|
||||||
|
# load user
|
||||||
|
self.load_user()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.check_heartbeat()
|
"""
|
||||||
|
检测心跳
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
self.check_heartbeat()
|
||||||
|
sleep(self.heartbeat_interval)
|
||||||
|
|
||||||
def check_heartbeat(self):
|
def check_heartbeat(self):
|
||||||
|
# 心跳检测
|
||||||
|
if self.last_heartbeat and (time_now() - self.last_heartbeat).seconds < self.heartbeat:
|
||||||
|
return True
|
||||||
if self.is_first_time() or not self.check_user_is_login():
|
if self.is_first_time() or not self.check_user_is_login():
|
||||||
self.handle_login()
|
self.handle_login()
|
||||||
pass
|
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_USER_HEARTBEAT_NORMAL.format(self.get_name(), self.heartbeat)).flush()
|
||||||
|
self.last_heartbeat = time_now()
|
||||||
|
|
||||||
# def init_cookies
|
# def init_cookies
|
||||||
def is_first_time(self):
|
def is_first_time(self):
|
||||||
return not self.get_user_cookie()
|
return not path.exists(self.get_cookie_path())
|
||||||
|
|
||||||
def handle_login(self):
|
def handle_login(self):
|
||||||
self.base_login()
|
UserLog.print_start_login(user=self)
|
||||||
|
self.login()
|
||||||
|
|
||||||
def base_login(self):
|
def login(self):
|
||||||
"""
|
"""
|
||||||
获取验证码结果
|
获取验证码结果
|
||||||
:return:
|
:return 权限校验码
|
||||||
"""
|
"""
|
||||||
data = {
|
data = {
|
||||||
'username': self.user_name,
|
'username': self.user_name,
|
||||||
'password': self.password,
|
'password': self.password,
|
||||||
'appid': 'otn'
|
'appid': 'otn'
|
||||||
}
|
}
|
||||||
|
answer = AuthCode.get_auth_code(self.session)
|
||||||
|
data['answer'] = answer
|
||||||
response = self.session.post(API_BASE_LOGIN.get('url'), data)
|
response = self.session.post(API_BASE_LOGIN.get('url'), data)
|
||||||
|
result = response.json()
|
||||||
|
if result.get('result_code') == 0: # 登录成功
|
||||||
|
"""
|
||||||
|
login 获得 cookie uamtk
|
||||||
|
auth/uamtk 不请求,会返回 uamtk票据内容为空
|
||||||
|
/otn/uamauthclient 能拿到用户名
|
||||||
|
"""
|
||||||
|
new_tk = self.auth_uamtk()
|
||||||
|
user_name = self.auth_uamauthclient(new_tk)
|
||||||
|
self.update_user_info({'user_name': user_name})
|
||||||
|
self.login_did_success()
|
||||||
|
elif result.get('result_code') == 2: # 账号之内错误
|
||||||
|
# 登录失败,用户名或密码为空
|
||||||
|
# 密码输入错误
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_LOGIN_FAIL.format(result.get('result_message')))
|
||||||
|
else:
|
||||||
|
UserLog.add_quick_log(
|
||||||
|
UserLog.MESSAGE_LOGIN_FAIL.format(result.get('result_message', result.get('message', '-'))))
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def check_user_is_login(self):
|
def check_user_is_login(self):
|
||||||
response = self.session.get(API_USER_CHECK.get('url'))
|
response = self.session.get(API_USER_CHECK.get('url'))
|
||||||
is_login = response.json().get('status')
|
is_login = response.json().get('data').get('flag', False)
|
||||||
|
if is_login:
|
||||||
|
self.save_user()
|
||||||
|
return is_login
|
||||||
|
|
||||||
def get_user_cookie(self):
|
def auth_uamtk(self):
|
||||||
path = self.get_cookie_path()
|
response = self.session.post(API_AUTH_UAMTK.get('url'), {'appid': 'otn'})
|
||||||
if path.exists(path):
|
result = response.json()
|
||||||
return open(path, encoding='utf-8').read()
|
if result.get('newapptk'):
|
||||||
return None
|
return result.get('newapptk')
|
||||||
|
# TODO 处理获取失败情况
|
||||||
|
return False
|
||||||
|
|
||||||
|
def auth_uamauthclient(self, tk):
|
||||||
|
response = self.session.post(API_AUTH_UAMAUTHCLIENT.get('url'), {'tk': tk})
|
||||||
|
result = response.json()
|
||||||
|
if result.get('username'):
|
||||||
|
return result.get('username')
|
||||||
|
# TODO 处理获取失败情况
|
||||||
|
return False
|
||||||
|
|
||||||
|
def login_did_success(self):
|
||||||
|
"""
|
||||||
|
用户登录成功
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.welcome_user()
|
||||||
|
self.save_user()
|
||||||
|
self.get_user_info()
|
||||||
|
pass
|
||||||
|
|
||||||
|
def welcome_user(self):
|
||||||
|
UserLog.print_welcome_user(self)
|
||||||
|
pass
|
||||||
|
|
||||||
def get_cookie_path(self):
|
def get_cookie_path(self):
|
||||||
return config.USER_DATA_DIR + '/' + self.user_name + '.cookie'
|
return config.USER_DATA_DIR + self.user_name + '.cookie'
|
||||||
|
|
||||||
|
def update_user_info(self, info):
|
||||||
|
self.info = {**self.info, **info}
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
return self.info.get('user_name')
|
||||||
|
|
||||||
|
def save_user(self):
|
||||||
|
with open(self.get_cookie_path(), 'wb') as f:
|
||||||
|
pickle.dump(self.session.cookies, f)
|
||||||
|
|
||||||
|
def did_loaded_user(self):
|
||||||
|
"""
|
||||||
|
恢复用户成功
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_LOADED_USER.format(self.user_name))
|
||||||
|
if self.check_user_is_login():
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_LOADED_USER_SUCCESS.format(self.user_name))
|
||||||
|
self.get_user_info()
|
||||||
|
UserLog.print_welcome_user(self)
|
||||||
|
else:
|
||||||
|
UserLog.add_quick_log(UserLog.MESSAGE_LOADED_USER_BUT_EXPIRED)
|
||||||
|
|
||||||
|
def get_user_info(self):
|
||||||
|
response = self.session.get(API_USER_INFO.get('url'))
|
||||||
|
result = response.json()
|
||||||
|
user_data = result.get('data')
|
||||||
|
if user_data.get('userDTO') and user_data['userDTO'].get('loginUserDTO'):
|
||||||
|
user_data = user_data['userDTO']['loginUserDTO']
|
||||||
|
self.update_user_info({**user_data, **{'user_name': user_data['name']}})
|
||||||
|
return True
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load_user(self):
|
||||||
|
cookie_path = self.get_cookie_path()
|
||||||
|
if path.exists(cookie_path):
|
||||||
|
with open(self.get_cookie_path(), 'rb') as f:
|
||||||
|
self.session.cookies.update(pickle.load(f))
|
||||||
|
self.did_loaded_user()
|
||||||
|
return True
|
||||||
|
return None
|
||||||
|
|||||||
@@ -19,10 +19,16 @@ class User:
|
|||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.init_users()
|
self.init_users()
|
||||||
UserLog.print_init_users(jobs=self.users)
|
UserLog.print_init_users(users=self.users)
|
||||||
while True:
|
while True:
|
||||||
|
# 多线程维护用户
|
||||||
|
threads = []
|
||||||
for user in self.users:
|
for user in self.users:
|
||||||
user.run()
|
thread = threading.Thread(target=user.run)
|
||||||
|
thread.start()
|
||||||
|
threads.append(thread)
|
||||||
|
# user.run()
|
||||||
|
for thread in threads: thread.join()
|
||||||
|
|
||||||
def init_users(self):
|
def init_users(self):
|
||||||
accounts = config.USER_ACCOUNTS
|
accounts = config.USER_ACCOUNTS
|
||||||
|
|||||||
54
py12306/vender/ruokuai/main.py
Executable file
54
py12306/vender/ruokuai/main.py
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
import requests
|
||||||
|
from hashlib import md5
|
||||||
|
|
||||||
|
|
||||||
|
class RKClient(object):
|
||||||
|
|
||||||
|
def __init__(self, username, password, soft_id, soft_key):
|
||||||
|
self.username = username
|
||||||
|
self.password = md5(password.encode('utf-8')).hexdigest()
|
||||||
|
self.soft_id = soft_id
|
||||||
|
self.soft_key = soft_key
|
||||||
|
self.base_params = {
|
||||||
|
'username': self.username,
|
||||||
|
'password': self.password,
|
||||||
|
'softid': self.soft_id,
|
||||||
|
'softkey': self.soft_key,
|
||||||
|
}
|
||||||
|
self.headers = {
|
||||||
|
'Connection': 'Keep-Alive',
|
||||||
|
'Expect': '100-continue',
|
||||||
|
'User-Agent': 'ben',
|
||||||
|
}
|
||||||
|
|
||||||
|
def rk_create(self, im, im_type, timeout=60):
|
||||||
|
"""
|
||||||
|
im: 图片字节
|
||||||
|
im_type: 题目类型
|
||||||
|
"""
|
||||||
|
params = {
|
||||||
|
'typeid': im_type,
|
||||||
|
'timeout': timeout,
|
||||||
|
}
|
||||||
|
params.update(self.base_params)
|
||||||
|
files = {'image': ('a.jpg', im)}
|
||||||
|
r = requests.post('http://api.ruokuai.com/create.json', data=params, files=files, headers=self.headers)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
def rk_report_error(self, im_id):
|
||||||
|
"""
|
||||||
|
im_id:报错题目的ID
|
||||||
|
"""
|
||||||
|
params = {
|
||||||
|
'id': im_id,
|
||||||
|
}
|
||||||
|
params.update(self.base_params)
|
||||||
|
r = requests.post('http://api.ruokuai.com/reporterror.json', data=params, headers=self.headers)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
rc = RKClient('username', 'password', 'soft_id', 'soft_key')
|
||||||
|
im = open('a.jpg', 'rb').read()
|
||||||
|
# print rc.rk_create(im, 3040)
|
||||||
|
|
||||||
Reference in New Issue
Block a user