diff --git a/README.md b/README.md index 6ef9d0e..2f7a08e 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,33 @@ -update:2020.10.19 -用requests库重写了一遍API库,大大提高了运行效率 +# 说明 +> 本脚本为安全微伴辅助学习脚本,嗯,懂得都懂 -原项目作者已停止维护该项目[原项目地址](https://github.com/WeiYuanStudio/AutoWeiBan) -由我接手更新了一些API接口和优化了原项目运行效率 +> 本项目Fork自[该项目](https://github.com/WeiYuanStudio/AutoWeiBan) -## 使用方法 -1. 首先需要在运行设备上安装Python3运行环境 -2. 接着打开命令行操作界面,CD(Change Directory)到该脚本的目录下 +## 使用方法 -3. 最后执行`python main.py` 或者 `python3 main.py`即可开始运行该脚本,按照指示使用即可。 +1. 首先需要在运行设备上安装Python3运行环境和requests库 +`pip intall requests` +2. 使用python自带的IDLE编辑运行目录下的main.py +3. 依据脚本提示二维码登录即可 ## 使用时请在main.py中将院校码修改为自己学校的院校码 +####补充:院校码可以在浏览器开发者工具中找到,如图 +![1.png](https://i.loli.net/2020/12/22/43JENwBjQIHiFqh.png) + +#### 更新日志: +> 2021.10.26 +修复请求接口,更改请求延迟 +(安全微伴疑似检测请求间隔) + +> 2021.4.10 +增加2021春季课程 + +旧脚本移至old文件夹 + +2020.12.22 + +fork[该项目](https://github.com/WeiYuanStudio/AutoWeiBan) + +修复报错,加入匹配课程、选修的课程学习 \ No newline at end of file diff --git a/WeiBanAPI.py b/WeiBanAPI.py index 3b75ea3..a1d3e3c 100644 --- a/WeiBanAPI.py +++ b/WeiBanAPI.py @@ -1,139 +1,155 @@ -from urllib import parse -import json -import random -import time -import requests -import os - -baseDelayTime = 1 # 基础延时秒数 - -randomDelayDeviation = 1 # 叠加随机延时差 - -getCookiesURL = 'https://weiban.mycourse.cn/#/login' # 请求Cookies URL - -loginURL = 'https://weiban.mycourse.cn/pharos/login/login.do' # 登录请求 URL - -getNameURL = 'https://weiban.mycourse.cn/pharos/my/getInfo.do' # 请求姓名 URL - -getProgressURL = 'https://weiban.mycourse.cn/pharos/project/showProgress.do' # 请求进度 URL - -getListCourseURL = 'https://weiban.mycourse.cn/pharos/usercourse/listCategory.do' # 请求课程种类 URL - -getListURL = 'https://weiban.mycourse.cn/pharos/usercourse/listCourse.do' # 请求课程列表URL - -finishCourseURL = 'https://weiban.mycourse.cn/pharos/usercourse/finish.do' # 请求完成课程URL - -getRandImageURL = 'https://weiban.mycourse.cn/pharos/login/randImage.do' # 验证码URL - -doStudyURL = 'https://weiban.mycourse.cn/pharos/usercourse/study.do' # 学习课程URL - -genQRCodeURL = 'https://weiban.mycourse.cn/pharos/login/genBarCodeImageAndCacheUuid.do' # 获取验证码以及验证码ID URL - -loginStatusURL = 'https://weiban.mycourse.cn/pharos/login/barCodeWebAutoLogin.do' # 用于二维码登录刷新登录状态 - - -# 二维码登录 -def qrLogin(): - qrCodeID = getQRCode() - - try: - while True: - responseText = getLoginStatus(qrCodeID) - responseJSON = json.loads(responseText) - if responseJSON['code'] == '0': - return responseJSON - else: - print('未登录,等待后5s刷新') - time.sleep(5) - except KeyboardInterrupt: - print('用户中止程序运行') - - -# 获取学生信息 -def getStuInfo(userId, tenantCode): - print('开始请求用户数据') - param = { - 'userId': userId, - 'tenantCode': tenantCode - } - req = requests.post(url=getNameURL, data=param) - responseJSON = json.loads(req.text) - return responseJSON - - -# 获取课程进度 -def getProgress(userProjectId, tenantCode): - param = { - 'userProjectId': userProjectId, - 'tenantCode': tenantCode - } - req = requests.post(url=getProgressURL, data=param) - responseJSON = json.loads(req.text) - return responseJSON - - -# 获取课程列表 -def getListCourse(userProjectId, chooseType, tenantCode): - param = { - 'userProjectId': userProjectId, - 'chooseType': chooseType, - 'tenantCode': tenantCode, - } - req = requests.post(url=getListCourseURL, data=param) - responseJSON = json.loads(req.text) - return responseJSON - -def GetList(userProjectId, categoryCode ,chooseType, tenantCode, name): - param = { - 'userProjectId': userProjectId, - 'categoryCode': categoryCode, - 'chooseType': chooseType, - 'tenantCode': tenantCode, - 'name': name - } - req = requests.post(url=getListURL, data=param) - responseJSON = json.loads(req.text) - return responseJSON - -# 完成课程请求 -def finishCourse(userCourseId, tenantCode): - param = { - 'userCourseId': userCourseId, - 'tenantCode': tenantCode, - } - url_values = parse.urlencode(param) # GET请求URL参数 - req = requests.get(url=finishCourseURL + '?' + url_values) - print(req.text) - - -def getRandomTime(): - return baseDelayTime + random.randint(0, randomDelayDeviation) - - -def doStudy(userProjectId, userCourseId, tenantCode): - param = { - 'userProjectId': userProjectId, - 'courseId': userCourseId, - 'tenantCode': tenantCode - } - req = requests.post(url=doStudyURL, data=param) - print(req.text) - return - - -# 获取并返回QRCode 链接以及 QRCode ID -def getQRCode(): - req = requests.post(url=genQRCodeURL) - responseJSON = json.loads(req.text) - print('请扫描二维码登录') - os.system('explorer {}'.format(responseJSON['data']['imagePath'])) - return responseJSON['data']['barCodeCacheUserId'] - - -# 用于二维码登录,刷新是否已经成功登录 -def getLoginStatus(qrCodeID): - param = { - 'barCodeCacheUserId': qrCodeID - } - req = requests.post(url=loginStatusURL, data=param) - return req.text +from urllib import parse +import json +import random +import time +import requests +import os + +baseDelayTime = 20 # 基础延时秒数 + +randomDelayDeviation = 20 # 叠加随机延时差 + +getCookiesURL = 'https://weiban.mycourse.cn/#/login' # 请求Cookies URL + +loginURL = 'https://weiban.mycourse.cn/pharos/login/login.do' # 登录请求 URL + +getNameURL = 'https://weiban.mycourse.cn/pharos/my/getInfo.do' # 请求姓名 URL + +getProgressURL = 'https://weiban.mycourse.cn/pharos/project/showProgress.do' # 请求进度 URL + +getListCourseURL = 'https://weiban.mycourse.cn/pharos/usercourse/listCategory.do' # 请求课程种类 URL + +getListURL = 'https://weiban.mycourse.cn/pharos/usercourse/listCourse.do' # 请求课程列表URL + +finishCourseURL = 'https://weiban.mycourse.cn/pharos/usercourse/finish.do' # 请求完成课程URL + +getRandImageURL = 'https://weiban.mycourse.cn/pharos/login/randImage.do' # 验证码URL + +doStudyURL = 'https://weiban.mycourse.cn/pharos/usercourse/study.do' # 学习课程URL + +genQRCodeURL = 'https://weiban.mycourse.cn/pharos/login/genBarCodeImageAndCacheUuid.do' # 获取验证码以及验证码ID URL + +loginStatusURL = 'https://weiban.mycourse.cn/pharos/login/barCodeWebAutoLogin.do' # 用于二维码登录刷新登录状态 + +getStudyTaskURL = 'https://weiban.mycourse.cn/pharos/index/getStudyTask.do' + +# 二维码登录 +def qrLogin(): + qrCodeID = getQRCode() + + try: + while True: + responseText = getLoginStatus(qrCodeID) + responseJSON = json.loads(responseText) + if responseJSON['code'] == '0': + responseInfo = getStudyTask(responseJSON['data']['userId'],responseJSON['data']['tenantCode']) + responseJSON['data']['normalUserProjectId']=responseInfo['data']['userProjectId'] + return responseJSON + else: + print('未登录,等待后5s刷新') + time.sleep(5) + except KeyboardInterrupt: + print('用户中止程序运行') + +def getStudyTask(userId, tenantCode): + print('开始请求最新课程: ') + param = { + 'userId': userId, + 'tenantCode': tenantCode + } + req = requests.post(url=getStudyTaskURL, data=param) + responseJSON = json.loads(req.text) + return responseJSON + +# 获取学生信息 +def getStuInfo(userId, tenantCode): + print('开始请求用户数据') + param = { + 'userId': userId, + 'tenantCode': tenantCode + } + req = requests.post(url=getNameURL, data=param) + responseJSON = json.loads(req.text) + return responseJSON + + +# 获取课程进度 +def getProgress(userProjectId, tenantCode): + param = { + 'userProjectId': userProjectId, + 'tenantCode': tenantCode + } + req = requests.post(url=getProgressURL, data=param) + responseJSON = json.loads(req.text) + return responseJSON + + +# 获取课程列表 +def getListCourse(userProjectId, chooseType, tenantCode): + param = { + 'userProjectId': userProjectId, + 'chooseType': chooseType, + 'tenantCode': tenantCode, + } + req = requests.post(url=getListCourseURL, data=param) + responseJSON = json.loads(req.text) + return responseJSON + +def GetList(userProjectId, categoryCode ,chooseType, tenantCode, name): + param = { + 'userProjectId': userProjectId, + 'categoryCode': categoryCode, + 'chooseType': chooseType, + 'tenantCode': tenantCode, + 'name': name + } + req = requests.post(url=getListURL, data=param) + responseJSON = json.loads(req.text) + return responseJSON + +# 完成课程请求 +def finishCourse(userCourseId, tenantCode): + param = { + 'callback':'jQuery0000', + 'userCourseId': userCourseId, + 'tenantCode': tenantCode, + '_': '1628328773' + } + url_values = parse.urlencode(param) # GET请求URL参数 + req = requests.get(url=finishCourseURL + '?' + url_values) + print(req.text) + + +def getRandomTime(): + return baseDelayTime + random.randint(0, randomDelayDeviation) + + +def doStudy(userProjectId, userCourseId, tenantCode,userId,token): + param = { + 'userProjectId': userProjectId, + 'courseId': userCourseId, + 'tenantCode': tenantCode, + 'userId': userId, + 'token': token + } + req = requests.post(url=doStudyURL, data=param) + print(req.text) + return + + +# 获取并返回QRCode 链接以及 QRCode ID +def getQRCode(): + req = requests.post(url=genQRCodeURL) + responseJSON = json.loads(req.text) + print('请扫描二维码登录') + os.system('explorer {}'.format(responseJSON['data']['imagePath'])) + return responseJSON['data']['barCodeCacheUserId'] + + +# 用于二维码登录,刷新是否已经成功登录 +def getLoginStatus(qrCodeID): + param = { + 'barCodeCacheUserId': qrCodeID + } + req = requests.post(url=loginStatusURL, data=param) + return req.text diff --git a/main.py b/main.py index 350f656..1921c7e 100644 --- a/main.py +++ b/main.py @@ -1,73 +1,75 @@ -import WeiBanAPI -import json -import time # time.sleep延时 -import os # 兼容文件系统 -import random - -tenantCode = '10422' # 院校ID - - -def main(): - loginResponse = WeiBanAPI.qrLogin() - - try: - print('登录成功,userName:' + loginResponse['data']['userName']) - except BaseException: - print('登录失败') - print(loginResponse) # TODO: 这里的loginResponse调用没有考虑网络错误等问题 - exit(0) - - # 请求解析并打印用户信息 - try: - print('请求用户信息') - stuInfoResponse = WeiBanAPI.getStuInfo(loginResponse['data']['userId'], - tenantCode) - print('用户信息:' + stuInfoResponse['data']['realName'] + '\n' - + stuInfoResponse['data']['orgName'] - + stuInfoResponse['data']['specialtyName'] - ) - except BaseException: - print('解析用户信息失败,将尝试继续运行,请注意运行异常') - - # 请求课程完成进度 - try: - getProgressResponse = WeiBanAPI.getProgress(loginResponse['data']['preUserProjectId'], - tenantCode) - print('课程总数:' + str(getProgressResponse['data']['requiredNum']) + '\n' - + '完成课程:' + str(getProgressResponse['data']['requiredFinishedNum']) + '\n' - + '结束时间' + str(getProgressResponse['data']['endTime']) + '\n' - + '剩余天数' + str(getProgressResponse['data']['lastDays']) - ) - except BaseException: - print('解析课程进度失败,将尝试继续运行,请注意运行异常') - - # 请求课程列表 - try: - getListCourseResponse = WeiBanAPI.getListCourse(loginResponse['data']['preUserProjectId'], - '3', - tenantCode) - except BaseException: - print('请求课程列表失败') - - print('解析课程列表并发送完成请求') - - for i in getListCourseResponse['data']: - print('\n----章节码:' + i['categoryCode'] + '章节内容:' + i['categoryName']) - NowClass = WeiBanAPI.GetList(loginResponse['data']['preUserProjectId'], - i['categoryCode'], - '3', - tenantCode, - '') - for j in NowClass['data']: - print('课程内容:' + j['resourceName'] + '\nuserCourseId:' + j['userCourseId']) - - if (j['finished'] == 1): - print('已完成') - else: - print('发送完成请求') - WeiBanAPI.doStudy(loginResponse['data']['preUserProjectId'], j['resourceId'], tenantCode) - WeiBanAPI.finishCourse(j['userCourseId'], tenantCode) - - -if __name__ == '__main__': - main() +import WeiBanAPI +import json +import time # time.sleep延时 +import os # 兼容文件系统 +import random + +tenantCode = '23333' # 院校ID + + +def main(): + loginResponse = WeiBanAPI.qrLogin() + + try: + print('登录成功,userName:' + loginResponse['data']['userName']) + except BaseException: + print('登录失败') + print(loginResponse) # TODO: 这里的loginResponse调用没有考虑网络错误等问题 + exit(0) + + # 请求解析并打印用户信息 + try: + print('请求用户信息') + stuInfoResponse = WeiBanAPI.getStuInfo(loginResponse['data']['userId'], + tenantCode) + print('用户信息:' + stuInfoResponse['data']['realName'] + '\n' + + stuInfoResponse['data']['orgName'] + + stuInfoResponse['data']['specialtyName'] + ) + except BaseException: + print('解析用户信息失败,将尝试继续运行,请注意运行异常') + + # 请求课程完成进度 + try: + getProgressResponse = WeiBanAPI.getProgress(loginResponse['data']['normalUserProjectId'], + tenantCode) + print('课程总数:' + str(getProgressResponse['data']['requiredNum']) + '\n' + + '完成课程:' + str(getProgressResponse['data']['requiredFinishedNum']) + '\n' + + '结束时间' + str(getProgressResponse['data']['endTime']) + '\n' + + '剩余天数' + str(getProgressResponse['data']['lastDays']) + ) + except BaseException: + print('解析课程进度失败,将尝试继续运行,请注意运行异常') + + # 请求课程列表 + try: + getListCourseResponse = WeiBanAPI.getListCourse(loginResponse['data']['normalUserProjectId'], + '3', + tenantCode) + except BaseException: + print('请求课程列表失败') + + print('解析课程列表并发送完成请求') + + for i in getListCourseResponse['data']: + print('\n----章节码:' + i['categoryCode'] + '章节内容:' + i['categoryName']) + NowClass = WeiBanAPI.GetList(loginResponse['data']['normalUserProjectId'], + i['categoryCode'], + '3', + tenantCode, + '') + for j in NowClass['data']: + print('课程内容:' + j['resourceName'] + '\nuserCourseId:' + j['userCourseId']) + + if (j['finished'] == 1): + print('已完成') + else: + print('发送完成请求') + WeiBanAPI.doStudy(loginResponse['data']['normalUserProjectId'], j['resourceId'], tenantCode,loginResponse['data']['userId'],loginResponse['data']['token']) + time.sleep(WeiBanAPI.getRandomTime()) + WeiBanAPI.finishCourse(j['userCourseId'], tenantCode) + print("✔✔✔必修课已完成✔✔✔") + + +if __name__ == '__main__': + main() diff --git a/old/main_2020.10.py b/old/main_2020.10.py new file mode 100644 index 0000000..83e1b2c --- /dev/null +++ b/old/main_2020.10.py @@ -0,0 +1,151 @@ +import WeiBanAPI +import json +import time # time.sleep延时 +import os # 兼容文件系统 +import random + +tenantCode = '233333' # 院校ID + + +def main(): + loginResponse = WeiBanAPI.qrLogin() + + try: + print('登录成功,userName:' + loginResponse['data']['userName']) + except BaseException: + print('登录失败') + print(loginResponse) # TODO: 这里的loginResponse调用没有考虑网络错误等问题 + exit(0) + + # 请求解析并打印用户信息 + try: + print('请求用户信息') + stuInfoResponse = WeiBanAPI.getStuInfo(loginResponse['data']['userId'], + tenantCode) + print('用户信息:' + stuInfoResponse['data']['realName'] + '\n' + + stuInfoResponse['data']['orgName'] + + stuInfoResponse['data']['specialtyName'] + ) + except BaseException: + print('解析用户信息失败,将尝试继续运行,请注意运行异常') + + # 请求课程完成进度 + try: + getProgressResponse = WeiBanAPI.getProgress(loginResponse['data']['normalUserProjectId'], + tenantCode) + print('课程总数:' + str(getProgressResponse['data']['requiredNum']) + '\n' + + '完成课程:' + str(getProgressResponse['data']['requiredFinishedNum']) + '\n' + + '结束时间' + str(getProgressResponse['data']['endTime']) + '\n' + + '剩余天数' + str(getProgressResponse['data']['lastDays']) + ) + except BaseException: + print('解析课程进度失败,将尝试继续运行,请注意运行异常') + + # 请求课程列表 + try: + getListCourseResponse = WeiBanAPI.getListCourse(loginResponse['data']['normalUserProjectId'], + '3', + tenantCode) + except BaseException: + print('请求课程列表失败') + + print('解析课程列表并发送完成请求') + + for i in getListCourseResponse['data']: + print('\n----章节码:' + i['categoryCode'] + '章节内容:' + i['categoryName']) + NowClass = WeiBanAPI.GetList(loginResponse['data']['normalUserProjectId'], + i['categoryCode'], + '3', + tenantCode, + '') + for j in NowClass['data']: + print('课程内容:' + j['resourceName'] + '\nuserCourseId:' + j['userCourseId']) + + if (j['finished'] == 1): + print('已完成') + else: + print('发送完成请求') + WeiBanAPI.doStudy(loginResponse['data']['normalUserProjectId'], j['resourceId'], tenantCode) + WeiBanAPI.finishCourse(j['userCourseId'], tenantCode) + print("✔✔✔必修课已完成✔✔✔") + #选修课 + print("匹配课程开始!") + try: + getProgressResponse = WeiBanAPI.getProgress(loginResponse['data']['normalUserProjectId'], + tenantCode) + print('课程总数:' + str(getProgressResponse['data']['requiredNum']) + '\n' + + '完成课程:' + str(getProgressResponse['data']['requiredFinishedNum']) + '\n' + + '结束时间' + str(getProgressResponse['data']['endTime']) + '\n' + + '剩余天数' + str(getProgressResponse['data']['lastDays']) + ) + except BaseException: + print('解析课程进度失败,将尝试继续运行,请注意运行异常') + + # 请求课程列表 + try: + getListCourseResponse = WeiBanAPI.getListCourse(loginResponse['data']['normalUserProjectId'], + '1', + tenantCode) + except BaseException: + print('请求课程列表失败') + + print('解析课程列表并发送完成请求') + + for i in getListCourseResponse['data']: + print('\n----章节码:' + i['categoryCode'] + '章节内容:' + i['categoryName']) + NowClass = WeiBanAPI.GetList(loginResponse['data']['normalUserProjectId'], + i['categoryCode'], + '1', + tenantCode, + '') + for j in NowClass['data']: + print('课程内容:' + j['resourceName'] + '\nuserCourseId:' + j['userCourseId']) + + if (j['finished'] == 1): + print('已完成') + else: + print('发送完成请求') + WeiBanAPI.doStudy(loginResponse['data']['normalUserProjectId'], j['resourceId'], tenantCode) + WeiBanAPI.finishCourse(j['userCourseId'], tenantCode) + print("✔✔✔匹配课已完成✔✔✔") + print("选修课开始!") + try: + getProgressResponse = WeiBanAPI.getProgress(loginResponse['data']['normalUserProjectId'], + tenantCode) + print('课程总数:' + str(getProgressResponse['data']['requiredNum']) + '\n' + + '完成课程:' + str(getProgressResponse['data']['requiredFinishedNum']) + '\n' + + '结束时间' + str(getProgressResponse['data']['endTime']) + '\n' + + '剩余天数' + str(getProgressResponse['data']['lastDays']) + ) + except BaseException: + print('解析课程进度失败,将尝试继续运行,请注意运行异常') + + # 请求课程列表 + try: + getListCourseResponse = WeiBanAPI.getListCourse(loginResponse['data']['normalUserProjectId'], + '2', + tenantCode) + except BaseException: + print('请求课程列表失败') + + print('解析课程列表并发送完成请求') + + for i in getListCourseResponse['data']: + print('\n----章节码:' + i['categoryCode'] + '章节内容:' + i['categoryName']) + NowClass = WeiBanAPI.GetList(loginResponse['data']['normalUserProjectId'], + i['categoryCode'], + '2', + tenantCode, + '') + for j in NowClass['data']: + print('课程内容:' + j['resourceName'] + '\nuserCourseId:' + j['userCourseId']) + + if (j['finished'] == 1): + print('已完成') + else: + print('发送完成请求') + WeiBanAPI.doStudy(loginResponse['data']['normalUserProjectId'], j['resourceId'], tenantCode) + WeiBanAPI.finishCourse(j['userCourseId'], tenantCode) + print("✔✔✔选修课已完成✔✔✔") +if __name__ == '__main__': + main() diff --git a/old/main_2021-4.py b/old/main_2021-4.py new file mode 100644 index 0000000..6b722a3 --- /dev/null +++ b/old/main_2021-4.py @@ -0,0 +1,73 @@ +import WeiBanAPI +import json +import time # time.sleep延时 +import os # 兼容文件系统 +import random + +tenantCode = '23333' # 院校ID + + +def main(): + loginResponse = WeiBanAPI.qrLogin() + + try: + print('登录成功,userName:' + loginResponse['data']['userName']) + except BaseException: + print('登录失败') + print(loginResponse) # TODO: 这里的loginResponse调用没有考虑网络错误等问题 + exit(0) + + # 请求解析并打印用户信息 + try: + print('请求用户信息') + stuInfoResponse = WeiBanAPI.getStuInfo(loginResponse['data']['userId'], + tenantCode) + print('用户信息:' + stuInfoResponse['data']['realName'] + '\n' + + stuInfoResponse['data']['orgName'] + + stuInfoResponse['data']['specialtyName'] + ) + except BaseException: + print('解析用户信息失败,将尝试继续运行,请注意运行异常') + + # 请求课程完成进度 + try: + getProgressResponse = WeiBanAPI.getProgress(loginResponse['data']['normalUserProjectId'], + tenantCode) + print('课程总数:' + str(getProgressResponse['data']['requiredNum']) + '\n' + + '完成课程:' + str(getProgressResponse['data']['requiredFinishedNum']) + '\n' + + '结束时间' + str(getProgressResponse['data']['endTime']) + '\n' + + '剩余天数' + str(getProgressResponse['data']['lastDays']) + ) + except BaseException: + print('解析课程进度失败,将尝试继续运行,请注意运行异常') + + # 请求课程列表 + try: + getListCourseResponse = WeiBanAPI.getListCourse(loginResponse['data']['normalUserProjectId'], + '3', + tenantCode) + except BaseException: + print('请求课程列表失败') + + print('解析课程列表并发送完成请求') + + for i in getListCourseResponse['data']: + print('\n----章节码:' + i['categoryCode'] + '章节内容:' + i['categoryName']) + NowClass = WeiBanAPI.GetList(loginResponse['data']['normalUserProjectId'], + i['categoryCode'], + '3', + tenantCode, + '') + for j in NowClass['data']: + print('课程内容:' + j['resourceName'] + '\nuserCourseId:' + j['userCourseId']) + + if (j['finished'] == 1): + print('已完成') + else: + print('发送完成请求') + WeiBanAPI.doStudy(loginResponse['data']['normalUserProjectId'], j['resourceId'], tenantCode) + WeiBanAPI.finishCourse(j['userCourseId'], tenantCode) + print("✔✔✔必修课已完成✔✔✔") + +if __name__ == '__main__': + main()