版本 2.0
This commit is contained in:
parent
043cbfcb9d
commit
9040dd3065
|
|
@ -1,5 +1,7 @@
|
|||
|
||||
__pycache__
|
||||
build
|
||||
dist
|
||||
__pycache__
|
||||
env
|
||||
*.bat
|
||||
*.json
|
||||
*.spec
|
||||
|
|
|
|||
60
README.md
60
README.md
|
|
@ -1,53 +1,39 @@
|
|||
# weiban-tool
|
||||
<h1 align="center">安全微伴自动刷课助手</h1>
|
||||
<p align="center" class="shields">
|
||||
<img src="https://badges.toozhao.com/badges/01HAMCFS652W02Z5H3CE02M4JY/blue.svg" alt="Visitors"/>
|
||||
</p>
|
||||
|
||||
安全微伴自动刷课助手
|
||||
相关项目:[安全微伴题库](https://github.com/pooneyy/WeibanQuestionsBank) | 安全微伴自动刷课助手
|
||||
|
||||
[原项目](https://github.com/Coaixy/weiban-tool)作者已停止维护,我在原项目基础上增加多账号的支持
|
||||
### 项目介绍
|
||||
|
||||
### 使用方法
|
||||
安全微伴自动刷课助手(多账号版),脱胎于[Coaixy/weiban-tool](https://github.com/Coaixy/weiban-tool),在原项目基础上增加多账号的支持,可以同时进行多个账号的学习任务。
|
||||
|
||||
1. 登录[安全微伴 (mycourse.cn)](http://weiban.mycourse.cn/#/login)。
|
||||
### 使用说明
|
||||
|
||||
2. 在浏览器地址栏运行
|
||||
1. 运行`main.py` 或者 [main.exe](https://github.com/pooneyy/weiban-tool/releases)。
|
||||
|
||||
```javascript
|
||||
javascript:(function(){data=JSON.parse(localStorage.user);prompt('',JSON.stringify({token:data['token'],userId:data['userId'], tenantCode:data['tenantCode'], userProjectId: data['preUserProjectId'], realName: data['realName']}));})();
|
||||
```
|
||||
2. **支持验证码识别**,验证码识别使用[TrueCaptcha](https://truecaptcha.org/),会提示你输入`userid`和`apikey`,注册的方法此处不过多赘述。
|
||||
|
||||
浏览器地址栏如果吞掉了“`javascript:`”,请手动加上。
|
||||
需要提醒的是,这是一个付费服务,每个账号每天享有30次免费识别服务,每个账号总共享有100次免费识别服务。
|
||||
|
||||
或者你可以将上述脚本[添加到收藏夹](https://www.qiuyelin.com/getWei-banToken.html),直接在登录后的页面上运行添加进收藏夹的脚本。
|
||||
关于资费,1美元可以识别3000次。可以使用PayPal国区支付,关于汇率,2023年9月18日,使用PayPal,$1USD=¥7.56CNY。
|
||||
|
||||
3. 复制弹窗内的内容,**按照格式**添加到`config.json`。(格式不对会报错)
|
||||
**值得一提的是,你可以跳过这一步骤,登录时将手动输入验证码。**
|
||||
|
||||
[](http://png.eot.ooo/i/2022/09/06/6316d7c7f3567.png)
|
||||
3. 按照提示录入账号密码,可同时依次输入多个账号,会记录上一个账号的学校名称,当有多个账号来自同一个学校,可以不用重复输入学校名。
|
||||
|
||||
4. 以`UTF-8`的编码方式创建`config.json`文件。其内容格式如下:
|
||||
4. 按`Ctrl`+`C`结束录入账号,开始登录,如果在第二步没有输入`userid`和`apikey`,会提示输入验证码。
|
||||
|
||||
> `config.json`:
|
||||
>
|
||||
> ```json
|
||||
> [
|
||||
> {"token":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","userId":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","tenantCode":"00000001","userProjectId":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"},
|
||||
> {"token":"yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy","userId":"yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy","tenantCode":"00000002","userProjectId":"yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"},
|
||||
> {"token":"zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz","userId":"zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz","tenantCode":"00000003","userProjectId":"zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz"},
|
||||
> {#第4个账号信息#},
|
||||
> {#第5个账号信息#},
|
||||
> ...
|
||||
> {#第n个账号信息#}
|
||||
> ]
|
||||
> ```
|
||||
|
||||
5. 运行`main.py` 或者 [main.exe](https://github.com/pooneyy/weiban-tool/releases)。
|
||||

|
||||
|
||||
### 更新日志
|
||||
|
||||
```text
|
||||
版本 1.1 at 2022-09-06 15:08:08
|
||||
优化:增加对多账户的支持。
|
||||
|
||||
版本 1.2 at 2022-09-07 14:02:39
|
||||
优化:使用异步函数,提高多账户场景下任务执行效率,避免由于多个账户排队时任务流程过长,Token过期,导致后面的账户任务失败。
|
||||
优化:使显示内容更简洁。
|
||||
```
|
||||
- 版本 1.1 at 2022-09-06 15:08:08
|
||||
- 优化:增加对多账户的支持。
|
||||
- 版本 1.2 at 2022-09-07 14:02:39
|
||||
- 优化:使用异步函数,提高多账户场景下任务执行效率,避免由于多个账户排队时任务流程过长,Token过期,导致后面的账户任务失败。
|
||||
- 优化:使显示内容更简洁。
|
||||
|
||||
- 版本 2.0 at 2023-09-18 21:57:16
|
||||
- 优化:使用账号密码登录,登录相关的代码来自[Coaixy/weiban-tool/enco.py](https://github.com/Coaixy/weiban-tool/blob/bf08fe823953afa834b49fe8d7e7a1d5abf7e605/enco.py)。
|
||||
|
|
|
|||
343
Utils.py
343
Utils.py
|
|
@ -1,26 +1,68 @@
|
|||
import time
|
||||
import requests
|
||||
import json
|
||||
import asyncio
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
from PIL import Image
|
||||
import random
|
||||
import requests
|
||||
import time
|
||||
|
||||
# From https://github.com/JefferyHcool/weibanbot/blob/main/enco.py
|
||||
from Cryptodome.Cipher import AES
|
||||
from Cryptodome.Util.Padding import pad
|
||||
import base64
|
||||
|
||||
DEFAULT_SCHOOL_NAME = ''
|
||||
'''这个常量的作用是暂存学校名,当同时输入的多个帐号来自同一个学校,用此避免重复地输入学校名'''
|
||||
|
||||
class main:
|
||||
tenantCode = 0
|
||||
userId = ""
|
||||
x_token = ""
|
||||
userProjectId = ""
|
||||
realName = ""
|
||||
taskName = ""
|
||||
resourceNames = ['第0项']
|
||||
headers = {'x-token': "",
|
||||
"User-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Mobile Safari/537.36 Edg/103.0.1264.77"
|
||||
}
|
||||
|
||||
def __init__(self, code, id, token,projectId):
|
||||
def __init__(self, code, id, token, realName):
|
||||
self.tenantCode = code
|
||||
self.userId = id
|
||||
self.x_token = token
|
||||
self.userProjectId = projectId
|
||||
self.realName = realName
|
||||
|
||||
def init(self):
|
||||
self.headers['x-token'] = self.x_token
|
||||
|
||||
# 以下俩个方法来自https://github.com/Sustech-yx/WeiBanCourseMaster
|
||||
|
||||
# js里的时间戳似乎都是保留了三位小数的.
|
||||
def __get_timestamp(self):
|
||||
return str(round(datetime.datetime.now().timestamp(), 3))
|
||||
|
||||
# Magic: 用于构造、拼接"完成学习任务"的url
|
||||
# js: (jQuery-3.2.1.min.js)
|
||||
# f = '3.4.1'
|
||||
# expando = 'jQuery' + (f + Math.random()).replace(/\D/g, "")
|
||||
def __gen_rand(self):
|
||||
return ("3.4.1" + str(random.random())).replace(".", "")
|
||||
|
||||
def get_Project_Info(self):
|
||||
url = f'https://weiban.mycourse.cn/pharos/index/listMyProject.do?timestamp={time.time()}'
|
||||
data = {
|
||||
'tenantCode': self.tenantCode,
|
||||
'userId': self.userId,
|
||||
'ended': 2
|
||||
}
|
||||
response = requests.post(url, data=data, headers=self.headers)
|
||||
data = json.loads(response.text)['data']
|
||||
if len(data) <= 0:self.userProjectId = ''
|
||||
else:
|
||||
self.userProjectId = data[0]["userProjectId"]
|
||||
self.taskName = data[0]["projectName"]
|
||||
|
||||
def getRealName(self):
|
||||
url = f"https://weiban.mycourse.cn/pharos/my/getInfo.do?timestamp={int(time.time())}"
|
||||
data = {
|
||||
|
|
@ -58,13 +100,13 @@ class main:
|
|||
data = json.loads(text)
|
||||
return data['data']['progressPet']
|
||||
|
||||
def getCategory(self):
|
||||
def getCategory(self, chooseType):
|
||||
url = "https://weiban.mycourse.cn/pharos/usercourse/listCategory.do"
|
||||
data = {
|
||||
'userProjectId': self.userProjectId,
|
||||
'tenantCode': self.tenantCode,
|
||||
'userId': self.userId,
|
||||
'chooseType': 3
|
||||
'chooseType': chooseType
|
||||
}
|
||||
response = requests.post(url, data=data, headers=self.headers)
|
||||
text = response.text
|
||||
|
|
@ -76,69 +118,278 @@ class main:
|
|||
result.append(i['categoryCode'])
|
||||
return result
|
||||
|
||||
def getCourse(self):
|
||||
def getCourse(self, chooseType):
|
||||
url = "https://weiban.mycourse.cn/pharos/usercourse/listCourse.do"
|
||||
result = []
|
||||
for i in self.getCategory():
|
||||
for i in self.getCategory(chooseType):
|
||||
data = {
|
||||
'userProjectId': self.userProjectId,
|
||||
'tenantCode': self.tenantCode,
|
||||
'userId': self.userId,
|
||||
'chooseType': 3,
|
||||
'name': "",
|
||||
'categoryCode': i
|
||||
"userProjectId": self.userProjectId,
|
||||
"tenantCode": self.tenantCode,
|
||||
"userId": self.userId,
|
||||
"chooseType": chooseType,
|
||||
"name": "",
|
||||
"categoryCode": i,
|
||||
}
|
||||
response = requests.post(url, data=data, headers=self.headers)
|
||||
text = response.text
|
||||
data = json.loads(text)['data']
|
||||
data = json.loads(text)["data"]
|
||||
for i in data:
|
||||
if i['finished'] == 2:
|
||||
result.append(i['resourceId'])
|
||||
if i["finished"] == 2:
|
||||
result.append(i["resourceId"])
|
||||
return result
|
||||
|
||||
def getFinishIdList(self):
|
||||
def getFinishIdList(self, chooseType):
|
||||
url = "https://weiban.mycourse.cn/pharos/usercourse/listCourse.do"
|
||||
result = {}
|
||||
for i in self.getCategory():
|
||||
for i in self.getCategory(chooseType):
|
||||
data = {
|
||||
'userProjectId': self.userProjectId,
|
||||
'tenantCode': self.tenantCode,
|
||||
'userId': self.userId,
|
||||
'chooseType': 3,
|
||||
'name': "",
|
||||
'categoryCode': i
|
||||
"userProjectId": self.userProjectId,
|
||||
"tenantCode": self.tenantCode,
|
||||
"userId": self.userId,
|
||||
"chooseType": chooseType,
|
||||
"categoryCode": i,
|
||||
}
|
||||
response = requests.post(url, data=data, headers=self.headers)
|
||||
text = response.text
|
||||
data = json.loads(text)['data']
|
||||
data = json.loads(text)["data"]
|
||||
for i in data:
|
||||
if i['finished'] == 2:
|
||||
result[i['resourceId']] = i['userCourseId']
|
||||
if i["finished"] == 2:
|
||||
if "userCourseId" in i:
|
||||
result[i["resourceId"]] = i["userCourseId"]
|
||||
# print(i['resourceName'])
|
||||
self.resourceNames.append(i['resourceName'])
|
||||
self.tempUserCourseId = i["userCourseId"]
|
||||
else:
|
||||
result[i["resourceId"]] = self.tempUserCourseId
|
||||
return result
|
||||
|
||||
|
||||
async def start(self,courseId):
|
||||
data = {
|
||||
'userProjectId': self.userProjectId,
|
||||
'tenantCode': self.tenantCode,
|
||||
'userId': self.userId,
|
||||
'courseId': courseId
|
||||
"userProjectId": self.userProjectId,
|
||||
"tenantCode": self.tenantCode,
|
||||
"userId": self.userId,
|
||||
"courseId": courseId,
|
||||
}
|
||||
headers = {
|
||||
"x-token":self.x_token
|
||||
}
|
||||
res = requests.post("https://weiban.mycourse.cn/pharos/usercourse/study.do",data=data,headers=headers)
|
||||
headers = {"x-token": self.x_token}
|
||||
res = requests.post(
|
||||
"https://weiban.mycourse.cn/pharos/usercourse/study.do",
|
||||
data=data,
|
||||
headers=headers,
|
||||
)
|
||||
while json.loads(res.text)['code'] == -1:
|
||||
await asyncio.sleep(5)
|
||||
res = requests.post("https://weiban.mycourse.cn/pharos/usercourse/study.do",data=data,headers=headers)
|
||||
res = requests.post(
|
||||
"https://weiban.mycourse.cn/pharos/usercourse/study.do",
|
||||
data=data,
|
||||
headers=headers,
|
||||
)
|
||||
print(f"start:{courseId}\r",end='')
|
||||
|
||||
def finish(self,finishId):
|
||||
params = {
|
||||
"callback":"",
|
||||
"userCourseId":finishId,
|
||||
"tenantCode":self.tenantCode
|
||||
def finish(self, courseId, finishId):
|
||||
get_url_url = "https://weiban.mycourse.cn/pharos/usercourse/getCourseUrl.do"
|
||||
finish_url = "https://weiban.mycourse.cn/pharos/usercourse/v1/{}.do"
|
||||
data = {
|
||||
"userProjectId": self.userProjectId,
|
||||
"tenantCode": self.tenantCode,
|
||||
"userId": self.userId,
|
||||
"courseId": courseId,
|
||||
}
|
||||
url = "https://weiban.mycourse.cn/pharos/usercourse/finish.do"
|
||||
requests.get(url=url,params=params)
|
||||
print(f"finish:{finishId}\r",end='')
|
||||
raw_data = requests.post(get_url_url, data=data, headers=self.headers)
|
||||
url = json.loads(raw_data.text.encode().decode("unicode-escape"))["data"]
|
||||
token = url[url.find("methodToken="): url.find("&csCom")].replace(
|
||||
"methodToken=", ""
|
||||
)
|
||||
# print(token)
|
||||
finish_url = finish_url.format(token)
|
||||
ts = self.__get_timestamp().replace(".", "")
|
||||
param = {
|
||||
"callback": "jQuery{}_{}".format(self.__gen_rand(), ts),
|
||||
"userCourseId": finishId,
|
||||
"tenantCode": self.tenantCode,
|
||||
"_": str(int(ts) + 1),
|
||||
}
|
||||
requests.get(finish_url, params=param, headers=self.headers).text
|
||||
print(f"{self.realName} Finish:{courseId}")
|
||||
|
||||
def fill_key(key):
|
||||
key_size = 128
|
||||
filled_key = key.ljust(key_size // 8, b'\x00')
|
||||
return filled_key
|
||||
|
||||
|
||||
def aes_encrypt(data, key):
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
ciphertext = cipher.encrypt(pad(data.encode('utf-8'), AES.block_size))
|
||||
base64_cipher = base64.b64encode(ciphertext).decode('utf-8')
|
||||
result_cipher = base64_cipher.replace('+', '-').replace('/', '_')
|
||||
return result_cipher
|
||||
|
||||
|
||||
def login(payload):
|
||||
init_key = 'xie2gg'
|
||||
key = fill_key(init_key.encode('utf-8'))
|
||||
|
||||
encrypted = aes_encrypt(
|
||||
f'{{"keyNumber":"{payload["userName"]}","password":"{payload["password"]}","tenantCode":"{payload["tenantCode"]}","time":{payload["timestamp"]},"verifyCode":"{payload["verificationCode"]}"}}',
|
||||
key
|
||||
)
|
||||
return encrypted
|
||||
|
||||
def apitruecaptcha(config, content):
|
||||
image=base64.b64encode(content)
|
||||
url = 'https://api.apitruecaptcha.org/one/gettext'
|
||||
data = {
|
||||
'data':str(image,'utf-8'),
|
||||
'userid':config["TrueCaptcha"]["userId"],
|
||||
'apikey':config["TrueCaptcha"]["apiKey"]
|
||||
}
|
||||
result = requests.post(url, json.dumps(data))
|
||||
res=result.json()
|
||||
try:verifycode = res['result']
|
||||
except:
|
||||
if res.get('success') == False:
|
||||
print(f"{res['error_type']} {res['error_message']}")
|
||||
if 'Credits' in res['error_message']:
|
||||
print("TrueCaptcha已达每日请求上限,无法再识别验证码。")
|
||||
return None
|
||||
else:verifycode = apitruecaptcha(config, content)
|
||||
elif res.get('message') == 'Internal server error':verifycode = apitruecaptcha(config, content)
|
||||
else:verifycode = apitruecaptcha(config, content)
|
||||
return verifycode
|
||||
|
||||
def get_tenant_code(school_name: str) -> str:
|
||||
tenant_list = requests.get(
|
||||
"https://weiban.mycourse.cn/pharos/login/getTenantListWithLetter.do"
|
||||
).text
|
||||
data = json.loads(tenant_list)["data"]
|
||||
for i in data:
|
||||
for j in i["list"]:
|
||||
if j["name"] == school_name:
|
||||
return j["code"]
|
||||
|
||||
def set_accounts():
|
||||
global DEFAULT_SCHOOL_NAME
|
||||
with open("config.json", "r+", encoding='utf8') as file:
|
||||
try:config = json.load(file)
|
||||
except:
|
||||
config = {}
|
||||
config['TrueCaptcha'] = None
|
||||
config['Accounts'] = []
|
||||
if config.get("TrueCaptcha") is None:
|
||||
print('验证码识别使用 TrueCaptcha.org,如果你想手动识别验证码,请按 Ctrl + C')
|
||||
try:
|
||||
config["TrueCaptcha"] = {}
|
||||
config["TrueCaptcha"]["userId"] = input('请输入 TrueCaptcha.org 的 userId:')
|
||||
config["TrueCaptcha"]["apiKey"] = input('请输入 TrueCaptcha.org 的 apiKey:')
|
||||
if config["TrueCaptcha"]["userId"] == '' or config["TrueCaptcha"]["apiKey"] == '':config["TrueCaptcha"] = None
|
||||
except KeyboardInterrupt:config["TrueCaptcha"] = None
|
||||
if config.get("TrueCaptcha") is None:print('\n你选择了手动识别验证码。\n')
|
||||
print('输入学校名、帐号、密码,结束输入请按 Ctrl + C')
|
||||
try:
|
||||
if config["Accounts"]:DEFAULT_SCHOOL_NAME = config["Accounts"][-1]['schoolName']
|
||||
while True:
|
||||
print(f'正在录入第 {len(config["Accounts"])+1} 个帐号')
|
||||
account = {}
|
||||
# 如果直接按回车,则将DEFAULT_SCHOOL_NAME的值赋给schoolName,否则将schoolName的值赋给DEFAULT_SCHOOL_NAME
|
||||
account['schoolName'] = input(f'请输入学校名称(当前默认学校为 {DEFAULT_SCHOOL_NAME}):')
|
||||
if account['schoolName'] == '':account['schoolName'] = DEFAULT_SCHOOL_NAME
|
||||
else:DEFAULT_SCHOOL_NAME = account['schoolName']
|
||||
account['id'] = input('请输入学号:')
|
||||
account['password'] = input('请输入密码:')
|
||||
account['State'] = 0
|
||||
if account['id'] == '' or account['password'] == '':
|
||||
print(f'\n停止输入账号,已保存 {len(config["Accounts"])} 个帐号')
|
||||
break
|
||||
config['Accounts'].append(account)
|
||||
except KeyboardInterrupt:print(f'\n停止输入账号,已保存 {len(config["Accounts"])} 个帐号')
|
||||
with open('config.json', 'w', encoding='utf8') as file:
|
||||
file.write(json.dumps(config, indent=4, ensure_ascii=False))
|
||||
print('配置已保存。\n')
|
||||
return config
|
||||
|
||||
def get_Login_State(config : dict, account : dict) -> dict:
|
||||
'''
|
||||
传入参数 config - 配置内容
|
||||
|
||||
传入参数 account - 一组账户信息
|
||||
```json
|
||||
{
|
||||
"schoolName": "XX学校",
|
||||
"id": "20230001",
|
||||
"password": "12345678",
|
||||
"State": 0
|
||||
}
|
||||
```
|
||||
以字典形式 返回该账户的登录态
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"userId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"tenantCode": "00000001",
|
||||
"realName": "张三"
|
||||
}
|
||||
```
|
||||
'''
|
||||
school_name = account['schoolName']
|
||||
tenant_code = get_tenant_code(school_name=school_name)
|
||||
user_id = account['id']
|
||||
user_pwd = account['password']
|
||||
now = time.time()
|
||||
# 打开验证码
|
||||
img_data = requests.get(f"https://weiban.mycourse.cn/pharos/login/randLetterImage.do?time={now}").content
|
||||
if config['TrueCaptcha'] is None:
|
||||
print("验证码链接:",end='')
|
||||
print(f"https://weiban.mycourse.cn/pharos/login/randLetterImage.do?time={now}")
|
||||
with open("code.jpg", "wb") as file:
|
||||
file.write(img_data)
|
||||
file.close()
|
||||
Image.open("code.jpg").show()
|
||||
# 获取验证码
|
||||
verity_code = input("请输入验证码:")
|
||||
os.remove("code.jpg")
|
||||
else:
|
||||
verity_code = apitruecaptcha(config, img_data)
|
||||
# 调用js方法
|
||||
payload = {
|
||||
"userName": user_id,
|
||||
"password": user_pwd,
|
||||
"tenantCode": tenant_code,
|
||||
"timestamp": now,
|
||||
"verificationCode": verity_code
|
||||
}
|
||||
ret = login(payload)
|
||||
request_data = {"data": ret}
|
||||
|
||||
response = requests.post(
|
||||
"https://weiban.mycourse.cn/pharos/login/login.do", data=request_data
|
||||
).text
|
||||
response = json.loads(response)
|
||||
if response['code'] == '0':
|
||||
tenantCode = response.get('data').get('tenantCode')
|
||||
userId = response.get('data').get('userId')
|
||||
x_token = response.get('data').get('token')
|
||||
realName = response.get('data').get('realName')
|
||||
print(f"用户 {user_id} {realName} 登录成功")
|
||||
return {"token":x_token,"userId":userId,"tenantCode":tenantCode,"realName":realName,"raw_id":user_id}
|
||||
elif "账号与密码不匹配" in response["msg"] or "账号已被锁定" in response["msg"] or "权限错误" in response["msg"]:
|
||||
print(f'用户 {user_id} 登录失败,错误码 {response["code"]} 原因为 {response["msg"]}')
|
||||
return {"is_locked":True,"raw_id":user_id}
|
||||
else:
|
||||
print(f'用户 {user_id} 登录失败,错误码 {response["code"]} 原因为 {response["msg"]}')
|
||||
return get_Login_State(config, account)
|
||||
|
||||
def save_Login_State(config):
|
||||
if config.get('Accounts_login_state') is None or len(config['Accounts_login_state']) == 0:
|
||||
config['Accounts_login_state'] = []
|
||||
for account in config.get("Accounts"):
|
||||
if account['State'] == 1:print(f'用户 {account["id"]} 已经完成,跳过登录')
|
||||
elif account['State'] == 0:
|
||||
login_State = get_Login_State(config, account)
|
||||
if login_State.get("is_locked") is True:account['State'] = -1
|
||||
else:config['Accounts_login_state'].append(login_State)
|
||||
elif account['State'] == -1:print(f'用户 {account["id"]} 密码错误,无法登录')
|
||||
with open('config.json', 'w', encoding='utf8') as file:file.write(json.dumps(config, indent=4, ensure_ascii=False))
|
||||
print('登录态已保存。\n')
|
||||
else:print('已存在登录态,跳过登录。\n')
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[
|
||||
{"token":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","userId":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","tenantCode":"00000001","userProjectId":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"},
|
||||
{"token":"yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy","userId":"yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy","tenantCode":"00000002","userProjectId":"yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"}
|
||||
]
|
||||
58
main.py
58
main.py
|
|
@ -2,38 +2,62 @@
|
|||
# @repo : https://github.com/pooneyy/weiban-tool
|
||||
|
||||
import os, sys
|
||||
import random
|
||||
import Utils
|
||||
import json
|
||||
import asyncio
|
||||
|
||||
async def weibanTask(user):
|
||||
# tenantCode UserId x-token userProjectId
|
||||
# tenantCode id x-token userProjectId
|
||||
tenantCode = user.get('tenantCode')
|
||||
userId = user.get('userId')
|
||||
x_token = user.get('token')
|
||||
userProjectId = user.get('userProjectId')
|
||||
realName = user.get('realName',userId)
|
||||
realName = user.get('realName')
|
||||
id = user.get('raw_id')
|
||||
taskName = '未知的任务名'
|
||||
main = Utils.main(tenantCode, userId, x_token, userProjectId)
|
||||
main = Utils.main(tenantCode, userId, x_token, realName)
|
||||
main.init()
|
||||
try:
|
||||
realName = main.getRealName()
|
||||
taskName = main.getTaskName()
|
||||
main.get_Project_Info()
|
||||
taskName = main.taskName
|
||||
print(f"开始进行 {realName} 的任务:{taskName}")
|
||||
finishIdList = main.getFinishIdList()
|
||||
for i in main.getCourse():
|
||||
await main.start(i)
|
||||
await asyncio.sleep(20)
|
||||
main.finish(finishIdList[i])
|
||||
print(f"{realName} 的任务已完成")
|
||||
except json.decoder.JSONDecodeError:print(f'{realName} 的账户信息错误或已经过期,请重新获取。详见:https://github.com/pooneyy/weiban-tool')
|
||||
# 获取列表
|
||||
for chooseType in [2,3]:
|
||||
finishIdList = main.getFinishIdList(chooseType)
|
||||
index = 1
|
||||
for i in main.getCourse(chooseType):
|
||||
print(f"{realName} 开始学习 {main.resourceNames[index]} {index} / {len(finishIdList)}")
|
||||
await main.start(i)
|
||||
await asyncio.sleep(random.randint(15,20))
|
||||
main.finish(i, finishIdList[i])
|
||||
print(f"{realName} 完成学习 {main.resourceNames[index]}")
|
||||
index += 1
|
||||
print(f"{id} {realName} 的任务已完成")
|
||||
with open("config.json", "r+", encoding='utf8') as file:
|
||||
config = json.load(file)
|
||||
for i in config['Accounts']:
|
||||
if i.get('id') == id:i['State'] = 1
|
||||
for i in config['Accounts_login_state']:
|
||||
if i.get('raw_id') == id:config['Accounts_login_state'].remove(i)
|
||||
# seek(0), truncate()用于覆写文件
|
||||
file.seek(0)
|
||||
file.truncate()
|
||||
json.dump(config, file, ensure_ascii=False, indent=4)
|
||||
except json.decoder.JSONDecodeError:
|
||||
print(f'{realName} 的账户登录态已经过期,已删除该登录态。请重新登录。')
|
||||
with open("config.json", "r+", encoding='utf8') as file:
|
||||
config = json.load(file)
|
||||
config['Accounts_login_state'] = []
|
||||
file.seek(0)
|
||||
file.truncate()
|
||||
json.dump(config, file, ensure_ascii=False, indent=4)
|
||||
except KeyboardInterrupt:print(f'{realName} 的任务被手动终止')
|
||||
|
||||
async def main():
|
||||
usersConfig = {}
|
||||
usersConfig = []
|
||||
try:
|
||||
with open("config.json", "r+", encoding='utf8') as file:
|
||||
try:usersConfig = json.load(file)
|
||||
try:usersConfig = json.load(file).get('Accounts_login_state')
|
||||
except json.decoder.JSONDecodeError:print('配置文件格式错误,请仔细检查 config.json 。详见:https://github.com/pooneyy/weiban-tool')
|
||||
tasks=[]
|
||||
for user in usersConfig:
|
||||
|
|
@ -43,6 +67,8 @@ async def main():
|
|||
except FileNotFoundError:print('未找到 config.json!详见:https://github.com/pooneyy/weiban-tool')
|
||||
|
||||
if __name__ =='__main__':
|
||||
try:asyncio.run(main())
|
||||
try:
|
||||
Utils.save_Login_State(Utils.set_accounts())
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:print(f'\n任务被手动终止')
|
||||
os.system("pause")
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
requests~=2.28.2
|
||||
DateTime~=5.1
|
||||
Pillow~=9.5.0
|
||||
pycryptodomex
|
||||
Loading…
Reference in New Issue