first commit

master
UnknownObject 10 months ago
commit 66d5c70ca8

10
.idea/.gitignore vendored

@ -0,0 +1,10 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# 屏蔽图片
.png

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

@ -0,0 +1,16 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyByteLiteralInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyPep8Inspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PyPep8NamingInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false">
<option name="ignoredErrors">
<list>
<option value="N802" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyRedundantParenthesesInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PyShadowingNamesInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
</profile>
</component>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/AnQuanWeiBan.iml" filepath="$PROJECT_DIR$/.idea/AnQuanWeiBan.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -0,0 +1,87 @@
import cv2
import requests
import os
import json
# 全局变量,用来存储点击的坐标和次数
clicks = []
count = 0
max_clicks = 0
def download_image(url):
try:
# 获取图片的内容
response = requests.get(url, stream=True)
response.raise_for_status() # 检查请求是否成功
# 从URL中提取图片文件名
filename = url.split("/")[-1]
# 确定保存路径
filepath = os.path.join(os.getcwd(), filename)
# 检查文件是否已经存在,若存在则删除旧文件
if os.path.exists(filepath):
os.remove(filepath)
print(f"文件 '{filename}' 已存在,旧文件已删除。")
# 以二进制写入方式保存图片
with open(filepath, 'wb') as file:
for chunk in response.iter_content(1024): # 分块下载
file.write(chunk)
return filepath # 返回保存的文件路径
except Exception as e:
print(f"Error: {e}")
return None
# 鼠标点击事件的回调函数
def mouse_callback(event, x, y, flags, param):
global count, max_clicks, clicks
# 如果检测到左键点击事件
if event == cv2.EVENT_LBUTTONDOWN:
if count < max_clicks:
count += 1
clicks.append((x, y))
# 在点击的位置绘制点击次数
cv2.putText(img, str(count), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('Image', img)
# 当达到指定的点击次数时,关闭窗口
if count >= max_clicks:
cv2.destroyAllWindows()
# 主函数,接受图片路径和点击次数
def captcha_main(image_path, num_clicks):
global img, max_clicks, clicks, count
clicks = []
count = 0
max_clicks = num_clicks
# 读取图像
img = cv2.imread(image_path)
if img is None:
print("Error: Could not load image.")
return
# 创建一个窗口并显示图片
cv2.namedWindow('Image')
cv2.imshow('Image', img)
# 设置鼠标点击回调函数
cv2.setMouseCallback('Image', mouse_callback)
# 等待用户关闭窗口
cv2.waitKey(0)
# 返回点击的坐标
pos_list = [{'x': x, 'y': y} for x, y in clicks]
return json.dumps(pos_list)
# if __name__ == "__main__":
# image_path = "G:\\Users\\15819\\Desktop\\14_3.png" # 替换为你的图片路径
# num_clicks = 3 # 替换为你需要的点击次数
# click_coordinates = captcha_main(image_path, num_clicks)
# print("点击的坐标: ", click_coordinates)

File diff suppressed because one or more lines are too long

@ -0,0 +1,89 @@
import time
import json
import weibanapi
x_token = '57ba12f6-8ef6-4d62-8103-cb97a1bd4bbe'
user_id = 'eec6b514-93d6-4516-9e6a-e45cc3ce980c'
user_project_id = '5fc7738e-f98c-4890-8ce8-d3b06d2649da'
tenant_code = '4137011066'
#jq_id = '3410029753790258616464'
# 1. showProgess 获取课程进度
# 2. listCategory 获取课程分类 传入userprojectid
# 3. listCourse 获取课程 传入categorycode
# 4. study 传入courseid(上一步获取的resourceid)
# 5. getCourseUrl 获取methodToken
# 6. checkFinish(验证码用的,直接跳过)
# 7. getNear(获取最近学习,没啥用,直接跳过)
# 8. 调用methodToken完成学习 参数callback(341+16位随机数+时间戳) _(时间戳)
def wait(text: str, ti: int):
while ti:
print(text % ti, end='')
time.sleep(1)
print('\r', end='')
ti = ti - 1
print(' \r', end='')
def main():
try:
w = weibanapi.WeibanAPI(x_token, user_id, user_project_id, tenant_code)
except Exception:
print('请检查初始化参数是否正确!')
exit(-1)
courseInfo = []
required, finished = w.showProgress()
print('{} 已完成{}'.format(required, finished))
# 获取课程分类
categorys = w.listCategory()
for c in categorys:
print("{}[{}/{}]".format(c["categoryName"], c["finishedNum"], c["totalNum"]))
# 如果该类课程学习数 < 总数 加入到courseInfo列表中
if c["totalNum"] > c["finishedNum"]:
courses = w.listCourse(c["categoryCode"])
for course in courses:
if course["finished"] == 2: # 根据观察 1是学了 2是没学
courseInfo.append(course)
for c in courseInfo:
userCourseId = c["userCourseId"]
resourceName = c["resourceName"]
categoryName = c["categoryName"]
resourceId = c["resourceId"]
print('开始学习{}-{}'.format(categoryName, resourceName))
code = w.study(resourceId)
if code != '0':
print('开始学习失败')
exit(-1)
# 学太快好像有可能学不上
wait('等待中.......%02d', 15)
retry_cnt = 0
captcha_id = w.DoCaptcha(userCourseId)
while (captcha_id is None) and (retry_cnt < 5):
retry_cnt = retry_cnt + 1
print(f'验证码未通过,正在重试第 {retry_cnt}')
captcha_id = w.DoCaptcha(userCourseId)
if (retry_cnt >= 5):
print('验证码重试次数达到上限,系统自动退出')
exit(-1)
tmp = w.MakeCourseFinish(captcha_id, userCourseId)
res = tmp[tmp.find('({') + 1:len(tmp) - 1]
print(f'tmp = [{tmp}], res = [{res}]')
j = json.loads(res)
if j["msg"] != "ok":
print('调用MakeCourseFinish失败!')
exit(-1)
wait('通过! %02d s后继续', 3)
if __name__ == '__main__':
print('免责声明: \n此程序仅供学习使用,由于个人操作引发的一系列后果与作者无关')
main()

@ -0,0 +1,208 @@
import datetime
import json
import random
import requests
import time
import captcha_img
def get_timestamp():
return str(round(datetime.datetime.now().timestamp(), 3))
def parseMethodToken(test: str):
return test[test.find('methodToken=') + 12:test.find('&csComm')]
#https://mcwk.mycourse.cn/course/A22002/A22002.html?userCourseId57051d99-434f-4814-81e7-84deee2128bb\u0026tenantCode\u003d4137011066\u0026type\u003d1\u0026csComm\u003dtrue\u0026csCapt\u003dtrue
#https://mcwk.mycourse.cn/course/A22002/A22002.html?userCourseId=57051d99-434f-4814-81e7-84deee2128bb&tenantCode=4137011066&type=1&csComm=true&csCapt=true
#https://mcwk.mycourse.cn/course/A22002/A22002.html?userCourseId=57051d99-434f-4814-81e7-84deee2128bb&tenantCode=4137011066&type=1&csComm=true&csCapt=true&userProjectId=5fc7738e-f98c-4890-8ce8-d3b06d2649da&userId=eec6b514-93d6-4516-9e6a-e45cc3ce980c&courseId=dd85f614-d32f-11eb-9a88-d4ae52bad611&projectType=special&projectId=undefined&protocol=true&link=34415&weiban=weiban&userName=f61f3acc85f34ae5802675ac194a5c38
#https://weiban.mycourse.cn/#/course/detail?courseId=dd85f614-d32f-11eb-9a88-d4ae52bad611&userProjectId=5fc7738e-f98c-4890-8ce8-d3b06d2649da&courseName=%E5%8F%8D%E6%81%90%E4%B9%8B%E3%80%8A%E5%8F%8D%E6%81%90%E6%B3%95%E3%80%8B%E7%AF%87&userCourseId=57051d99-434f-4814-81e7-84deee2128bb&link=34415&projectType=special
def GetTimeStampMS():
return str(int(round(time.time() * 1000)))
class WeibanAPI:
tenantCode = ''
x_token = ' '
userId = ' '
userProjectId = ' '
headers = None
captcha_headers = None
def __init__(self, token, user_id, user_project_id, tenant_code):
self.x_token = token
self.tenantCode = tenant_code
self.userId = user_id
self.userProjectId = user_project_id
self.headers = {
'X-Token': self.x_token,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203'
}
self.captcha_headers = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203',
'Referer': 'https://mcwk.mycourse.cn/'
}
res = self._showProgress()
if len(res) == 0:
raise Exception('failed to get course info')
def showProgress(self):
res = self._showProgress()
j = json.loads(res)
return j["data"]["requiredNum"], j["data"]["requiredFinishedNum"]
def _showProgress(self):
url = 'https://weiban.mycourse.cn/pharos/project/showProgress.do?timestamp=' + get_timestamp()
data = {
'tenantCode': self.tenantCode,
'userId': self.userId,
'userProjectId': self.userProjectId
}
return self.process_url(url, data)
def _process_url(self, url, param, method):
if method == 'POST':
re = requests.post(url=url, data=param, headers=self.headers)
elif method == 'GET':
url += '?'
for key, item in param.items():
url = url + ('' if url.endswith('?') else '&') + str(key) + '=' + str(item)
re = requests.get(url=url, headers=self.headers)
else:
raise ValueError('WRONG METHOD')
return re.text
def process_url(self, url, param, method='POST'):
return self._process_url(url, param, method)
def _listCategory(self):
url = 'https://weiban.mycourse.cn/pharos/usercourse/listCategory.do?timestamp=' + get_timestamp()
data = {
'tenantCode': self.tenantCode,
'userId': self.userId,
'userProjectId': self.userProjectId,
'chooseType': 3
}
return self.process_url(url, data)
def listCategory(self):
ret = self._listCategory()
try:
j = json.loads(ret)
return j["data"]
except json.decoder.JSONDecodeError as e:
print(e.msg)
def _listCourse(self, category_code):
url = 'https://weiban.mycourse.cn/pharos/usercourse/listCourse.do?timestamp=' + get_timestamp()
data = {
'tenantCode': self.tenantCode,
'userId': self.userId,
'userProjectId': self.userProjectId,
'chooseType': 3,
'categoryCode': category_code
}
return self.process_url(url, data)
def listCourse(self, category_code):
ret = self._listCourse(category_code)
try:
j = json.loads(ret)
return j["data"]
except json.decoder.JSONDecodeError as e:
print(e.msg)
def _getCourseUrl(self, resource_id):
url = 'https://weiban.mycourse.cn/pharos/usercourse/getCourseUrl.do?timestamp=' + get_timestamp()
data = {
'tenantCode': self.tenantCode,
'userId': self.userId,
'userProjectId': self.userProjectId,
'courseId': resource_id
}
return self.process_url(url, data)
def getCourseUrl(self, resource_id):
ret = self._getCourseUrl(resource_id)
try:
j = json.loads(ret)
return j["data"]
except json.decoder.JSONDecodeError as e:
print(e.msg)
def methodToken(self, method_token, user_course_id):
url = 'https://weiban.mycourse.cn/pharos/usercourse/v1/{}.do'.format(method_token)
t = get_timestamp().replace('.', '')
param = {
'callback': 'jQuery341' + str(random.random()).replace('.', '') + '_' + t,
'userCourseId': user_course_id,
'tenantCode': self.tenantCode,
'_': int(t) + 1
}
return self.process_url(url, param, 'GET')
def CheckCaptcha(self, url, answer):
payload = {"coordinateXYs": answer}
return requests.post(url, data=payload, headers=self.captcha_headers).text
def DoCaptcha(self, user_course_id):
get_url = 'https://weiban.mycourse.cn/pharos/usercourse/getCaptcha.do'
check_url = 'https://weiban.mycourse.cn/pharos/usercourse/checkCaptcha.do'
#?userCourseId={}&userProjectId={}&userId={}&tenantCode={}
param = {
'userCourseId': user_course_id,
'userProjectId': self.userProjectId,
'userId': self.userId,
'tenantCode': self.tenantCode
}
try:
captcha_data = json.loads(self.process_url(get_url, param, 'GET'))
captcha_num = captcha_data["captcha"]["num"]
captcha_id = captcha_data["captcha"]["questionId"]
captcha_image = captcha_img.download_image(captcha_data["captcha"]["imageUrl"])
if(captcha_image is None):
print('【错误】无法下载验证码')
return None
answer_pos = captcha_img.captcha_main(captcha_image, captcha_num)
full_check_url = f'{check_url}?userCourseId={user_course_id}&userProjectId={self.userProjectId}&userId={self.userId}&tenantCode={self.tenantCode}&questionId={captcha_id}'
captcha_result = json.loads(self.CheckCaptcha(full_check_url, answer_pos))
if((captcha_result["code"] != "0") or (captcha_result["data"]["checkResult"] != 1)):
print('【错误】验证码未通过')
return None
return captcha_result["data"]["methodToken"]
except json.decoder.JSONDecodeError as e:
print(f'JSON Error: {e.msg}')
return None
def MakeCourseFinish(self, captcha_token, user_course_id):
url = 'https://weiban.mycourse.cn/pharos/usercourse/v2/{}.do'.format(captcha_token)
t = GetTimeStampMS()
param = {
'callback': 'jQuery341' + str(random.random()).replace('.', '') + '_' + t,
'userCourseId': user_course_id,
'tenantCode': self.tenantCode,
'_': int(t) + 1
}
return self.process_url(url, param, 'GET')
def study(self, resource_id):
res = self._study(resource_id)
try:
j = json.loads(res)
return j["code"]
except json.decoder.JSONDecodeError as e:
print(e.msg)
def _study(self, resource_id):
url = 'https://weiban.mycourse.cn/pharos/usercourse/study.do?timestamp=' + get_timestamp()
data = {
'tenantCode': self.tenantCode,
'userId': self.userId,
'userProjectId': self.userProjectId,
'courseId': resource_id
}
return self.process_url(url, data)
Loading…
Cancel
Save