├── # environment.yml ├── .gitignore ├── PngsGroup1 ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── CentPlay.png ├── Finished.png ├── NotCorrect.png ├── OptionA.png ├── OptionB.png ├── OptionC.png ├── OptionD.png ├── Options.png ├── Pause.png ├── Replay.png ├── Submit.png ├── UnplayNumbers.png ├── cx_point.png ├── zh_caution.png ├── zh_closeQuestion.png ├── zh_finished.png ├── zh_optionA.png ├── zh_optionB.png ├── zh_play.png ├── zh_played.png ├── zh_question.png ├── zh_skipCaution.png └── zh_unplay.png ├── PngsGroup2 ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── CentPlay.png ├── Finished.png ├── NotCorrect.png ├── OptionA.png ├── OptionB.png ├── OptionC.png ├── OptionD.png ├── Options.png ├── Pause.png ├── Replay.png ├── Submit.png ├── UnplayNumbers.png ├── cx_point.png ├── zh_caution.png ├── zh_closeQuestion.png ├── zh_finished.png ├── zh_optionA.png ├── zh_optionB.png ├── zh_played.png ├── zh_question.png ├── zh_skipCaution.png └── zh_unplay.png ├── README.md ├── Run_awClass.bat ├── codes ├── AwClass_3.0.py ├── ChangeRes.py ├── ResetRes.py ├── SetDpi.exe ├── UserFile.txt └── test.py └── 恢复分辨率.bat /# environment.yml: -------------------------------------------------------------------------------- 1 | # environment.yml 2 | 3 | name: dev310 4 | channels: 5 | - defaults 6 | dependencies: 7 | - bzip2=1.0.8=he774522_0 8 | - ca-certificates=2023.12.12=haa95532_0 9 | - libffi=3.4.4=hd77b12b_0 10 | - openssl=3.0.13=h2bbff1b_0 11 | - pip=23.3.1=py310haa95532_0 12 | - python=3.10.13=he1021f5_0 13 | - setuptools=68.2.2=py310haa95532_0 14 | - sqlite=3.41.2=h2bbff1b_0 15 | - tk=8.6.12=h2bbff1b_0 16 | - tzdata=2024a=h04d1e81_0 17 | - vc=14.2=h21ff451_1 18 | - vs2015_runtime=14.27.29016=h5e58377_2 19 | - wheel=0.41.2=py310haa95532_0 20 | - xz=5.4.5=h8cc25b3_0 21 | - zlib=1.2.13=h8cc25b3_0 22 | - pip: 23 | - mouseinfo==0.1.3 24 | - numpy==1.26.4 25 | - opencv-python==4.9.0.80 26 | - pillow==10.2.0 27 | - pyautogui==0.9.54 28 | - pygetwindow==0.0.9 29 | - pymsgbox==1.0.9 30 | - pyperclip==1.8.2 31 | - pypiwin32==223 32 | - pyrect==0.2.0 33 | - pyscreeze==0.1.30 34 | - pytweening==1.2.0 35 | - pywin32==306 36 | prefix: C:\Users\spp90\anaconda3\envs\dev310 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | codes/userFile.txt -------------------------------------------------------------------------------- /PngsGroup1/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/1.png -------------------------------------------------------------------------------- /PngsGroup1/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/2.png -------------------------------------------------------------------------------- /PngsGroup1/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/3.png -------------------------------------------------------------------------------- /PngsGroup1/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/4.png -------------------------------------------------------------------------------- /PngsGroup1/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/5.png -------------------------------------------------------------------------------- /PngsGroup1/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/6.png -------------------------------------------------------------------------------- /PngsGroup1/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/7.png -------------------------------------------------------------------------------- /PngsGroup1/CentPlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/CentPlay.png -------------------------------------------------------------------------------- /PngsGroup1/Finished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/Finished.png -------------------------------------------------------------------------------- /PngsGroup1/NotCorrect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/NotCorrect.png -------------------------------------------------------------------------------- /PngsGroup1/OptionA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/OptionA.png -------------------------------------------------------------------------------- /PngsGroup1/OptionB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/OptionB.png -------------------------------------------------------------------------------- /PngsGroup1/OptionC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/OptionC.png -------------------------------------------------------------------------------- /PngsGroup1/OptionD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/OptionD.png -------------------------------------------------------------------------------- /PngsGroup1/Options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/Options.png -------------------------------------------------------------------------------- /PngsGroup1/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/Pause.png -------------------------------------------------------------------------------- /PngsGroup1/Replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/Replay.png -------------------------------------------------------------------------------- /PngsGroup1/Submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/Submit.png -------------------------------------------------------------------------------- /PngsGroup1/UnplayNumbers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/UnplayNumbers.png -------------------------------------------------------------------------------- /PngsGroup1/cx_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/cx_point.png -------------------------------------------------------------------------------- /PngsGroup1/zh_caution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_caution.png -------------------------------------------------------------------------------- /PngsGroup1/zh_closeQuestion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_closeQuestion.png -------------------------------------------------------------------------------- /PngsGroup1/zh_finished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_finished.png -------------------------------------------------------------------------------- /PngsGroup1/zh_optionA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_optionA.png -------------------------------------------------------------------------------- /PngsGroup1/zh_optionB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_optionB.png -------------------------------------------------------------------------------- /PngsGroup1/zh_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_play.png -------------------------------------------------------------------------------- /PngsGroup1/zh_played.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_played.png -------------------------------------------------------------------------------- /PngsGroup1/zh_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_question.png -------------------------------------------------------------------------------- /PngsGroup1/zh_skipCaution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_skipCaution.png -------------------------------------------------------------------------------- /PngsGroup1/zh_unplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup1/zh_unplay.png -------------------------------------------------------------------------------- /PngsGroup2/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/1.png -------------------------------------------------------------------------------- /PngsGroup2/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/2.png -------------------------------------------------------------------------------- /PngsGroup2/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/3.png -------------------------------------------------------------------------------- /PngsGroup2/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/4.png -------------------------------------------------------------------------------- /PngsGroup2/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/5.png -------------------------------------------------------------------------------- /PngsGroup2/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/6.png -------------------------------------------------------------------------------- /PngsGroup2/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/7.png -------------------------------------------------------------------------------- /PngsGroup2/CentPlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/CentPlay.png -------------------------------------------------------------------------------- /PngsGroup2/Finished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/Finished.png -------------------------------------------------------------------------------- /PngsGroup2/NotCorrect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/NotCorrect.png -------------------------------------------------------------------------------- /PngsGroup2/OptionA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/OptionA.png -------------------------------------------------------------------------------- /PngsGroup2/OptionB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/OptionB.png -------------------------------------------------------------------------------- /PngsGroup2/OptionC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/OptionC.png -------------------------------------------------------------------------------- /PngsGroup2/OptionD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/OptionD.png -------------------------------------------------------------------------------- /PngsGroup2/Options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/Options.png -------------------------------------------------------------------------------- /PngsGroup2/Pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/Pause.png -------------------------------------------------------------------------------- /PngsGroup2/Replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/Replay.png -------------------------------------------------------------------------------- /PngsGroup2/Submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/Submit.png -------------------------------------------------------------------------------- /PngsGroup2/UnplayNumbers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/UnplayNumbers.png -------------------------------------------------------------------------------- /PngsGroup2/cx_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/cx_point.png -------------------------------------------------------------------------------- /PngsGroup2/zh_caution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_caution.png -------------------------------------------------------------------------------- /PngsGroup2/zh_closeQuestion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_closeQuestion.png -------------------------------------------------------------------------------- /PngsGroup2/zh_finished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_finished.png -------------------------------------------------------------------------------- /PngsGroup2/zh_optionA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_optionA.png -------------------------------------------------------------------------------- /PngsGroup2/zh_optionB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_optionB.png -------------------------------------------------------------------------------- /PngsGroup2/zh_played.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_played.png -------------------------------------------------------------------------------- /PngsGroup2/zh_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_question.png -------------------------------------------------------------------------------- /PngsGroup2/zh_skipCaution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_skipCaution.png -------------------------------------------------------------------------------- /PngsGroup2/zh_unplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/PngsGroup2/zh_unplay.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoOnlineClass 2 | 3 | 超星尔雅以及智慧树平台网课自动刷视频 4 | 基于pyautogui的模拟鼠标操作 5 | 6 | ## 使用方法 7 | 8 | 下载所有代码的.zip文件 9 | 10 | 保证电脑中有python运行环境,开发环境为python3.11.5 11 | 12 | 运行.bat文件 或者 直接运行codes文件夹中的AwClass_3.0.py 13 | 14 | 15 | 16 | ############# 17 | 18 | 脚本会自动下载所需的对应版本的依赖库 19 | 20 | 建议使用虚拟环境!!! 电脑中存在的不同版本的库可能导致冲突 21 | 22 | 经验证的conda环境已导出为environment.yml 23 | 24 | ############# 25 | 26 | 27 | ![图片](https://github.com/user-attachments/assets/0ba07a30-618f-4bd9-81d0-e60174db85bb) 28 | 在设置菜单中设置好参数。 29 | 30 | ![图片](https://github.com/user-attachments/assets/615965b3-5c32-4302-851f-166c089c541f) 31 | 超星尔雅平台需要调整至如上界面,将浏览器全屏。 32 | 33 | 点击设置菜单的确认按钮,5秒后脚本开始运行。 34 | 关闭cmd窗口即中止运行 35 | 36 | 37 | 38 | ## 注意 39 | 40 | png图片均是在分辨率2560x1440,125%缩放下截图 41 | 若在Windows设置菜单里能够找到这种显示设置,那么分辨率和缩放可以在Gui里一键调整。 42 | 如果在设置里不包含这种显示设置,请自行搜索添加方法(当然你也可以选择手动调整显示设置或者自己截取png图片)。 43 | 44 | 45 | 可以自行添加PngsGroup图片组以适应网课平台的变化,确保对应图片名称正确完整 46 | 图片放在名称为PngsGroup + (序号) 的文件夹中,可以在gui中选择对应序号的图片组 47 | 48 | 由于这是个边学边做的项目,很多东西都不完善,敬请谅解。 49 | 50 | ## 未来计划 51 | 52 | -图组图例 53 | -更多使用说明 54 | -最大播放视频数 55 | -------------------------------------------------------------------------------- /Run_awClass.bat: -------------------------------------------------------------------------------- 1 | python .\codes\AwClass_3.0.py -------------------------------------------------------------------------------- /codes/AwClass_3.0.py: -------------------------------------------------------------------------------- 1 | #Every png is captured in the resolution of 2560x1440 and the windows scale of 125%. 2 | #Any other display profile is not guaranteed to work. 3 | #智慧树平台由于长宽比例缩放原因,仅在firefox中可用 4 | 5 | import subprocess 6 | try: 7 | import pyautogui as pag 8 | import cv2 9 | import time 10 | import tkinter as tk 11 | from os import path 12 | from win32 import win32api 13 | import win32con 14 | import pywintypes 15 | except ImportError: 16 | print('安装依赖库') 17 | subprocess.call(['pip','install','numpy==1.24.3']) 18 | subprocess.call(['pip','install','pyautogui==0.9.54']) 19 | subprocess.call(['pip','install','opencv-python==4.9.0.80']) 20 | subprocess.call(['pip','install','pywin32==306']) 21 | subprocess.call(['pip','install','pypiwin32==223']) 22 | 23 | import pyautogui as pag 24 | import cv2 25 | import time 26 | import tkinter as tk 27 | from os import path 28 | from win32 import win32api 29 | import win32con 30 | import pywintypes 31 | 32 | cwd = path.abspath(path.dirname(__file__)) 33 | pngsGroupLocation = path.abspath(path.join(cwd, path.pardir)) + r'\PngsGroup' 34 | pag.PAUSE = 0 35 | pngsLocation = '' 36 | print(pngsLocation) 37 | 38 | 39 | """ 40 | 以下为分辨率处理函数 41 | """ 42 | 43 | def resetResolution(): 44 | try: 45 | with open(cwd + r'\UserFile.txt', 'r') as userFile: 46 | fileInput = userFile.readlines() 47 | userWidth = int(fileInput[2]) 48 | userHeight = int(fileInput[4]) 49 | userScale = int(fileInput[6]) 50 | except: 51 | print("无法处理配置文件,删除\"UserFile.txt\"后重试") 52 | print("读取的文件为:",fileInput) 53 | quit() 54 | 55 | userFile = open(cwd + r'\UserFile.txt', 'w') 56 | userFile.writelines(['Resolution has been reset once. ', 'Manually configuring your resolution and scale ratio if there any problem.']) 57 | userFile.writelines(['\nWidth=\n', str(userWidth),'\nHeight=\n',str(userHeight),'\nScale=\n',str(userScale)]) 58 | userFile.close() 59 | 60 | #更改分辨率 61 | devmode = pywintypes.DEVMODEType() 62 | 63 | devmode.PelsWidth = userWidth 64 | devmode.PelsHeight = userHeight 65 | 66 | devmode.Fields = win32con.DM_PELSWIDTH | win32con.DM_PELSHEIGHT 67 | 68 | win32api.ChangeDisplaySettings(devmode, 0) 69 | 70 | #更改缩放 71 | win32api.ShellExecute(0, 'open', cwd+'\SetDpi.exe', ' '+str(userScale), '', 0) 72 | 73 | def changeResolution(): 74 | #运行调整分辨率的程序 75 | #由于PyautoGUI与获取Windows缩放的代码有冲突 76 | #会导致获取的缩放始终为100% 77 | #暂时使用另一程序实现 78 | subprocess.call(["python", cwd + r'\ChangeRes.py']) 79 | 80 | """ 81 | 以下为通用的封装函数 82 | """ 83 | 84 | def qLocate(pngName:str, confidenceValve = 0.9): 85 | """ 86 | 重新封装的找图函数 87 | 88 | :param pngName: png格式的图片名称(不包含后缀名) 89 | :param confidenceValve: 找图的置信值,默认为0.9 90 | :return: PyAutoGUI定义的找图返回值,未找到则返回None 91 | """ 92 | pathName = pngsLocation + '\\' + pngName + '.png' 93 | try: 94 | tempLocation = pag.locateOnScreen(pathName, confidence=confidenceValve) 95 | except pag.ImageNotFoundException: 96 | return None 97 | else: 98 | return tempLocation 99 | 100 | def mouseMove(pngLocate, biasX=0, biasY=0): 101 | """ 102 | 封装的鼠标移动和点击函数,移动到图片加偏移的位置,等待500ms后点击 103 | 104 | :param pngLocate: PyAutoGUI定义的图片类型 105 | :param biasX: X轴方向上的坐标偏移 106 | :param biasY: Y轴方向上的坐标偏移 107 | """ 108 | if not pngLocate is None: 109 | x1, y1 = pag.center(pngLocate) 110 | print(x1,' ',y1) 111 | pag.moveTo(x1 + biasX, y1+biasY, 0.3, pag.easeOutQuad) 112 | time.sleep(0.5) 113 | pag.click() 114 | 115 | 116 | 117 | """ 118 | 以下为UI部分 119 | """ 120 | 121 | def exitProgram(): 122 | #手动关闭窗口的回调函数 123 | #退出程序 124 | setupWindow.destroy() 125 | exit() 126 | 127 | def displayOption(): 128 | #选择超星尔雅平台后的回调函数 129 | #显示第二项选项 130 | lb2.grid(column=0, row=3, sticky=tk.W) 131 | rad2_1.grid(column=0, row=4, sticky=tk.W) 132 | rad2_2.grid(column=1, row=4, sticky=tk.W) 133 | 134 | def undisplayOption(): 135 | #选择超星尔雅平台的回调函数 136 | #取消显示第二项选项 137 | lb2.grid_forget() 138 | rad2_1.grid_forget() 139 | rad2_2.grid_forget() 140 | 141 | 142 | 143 | def displaySetupGui(): 144 | global setupWindow 145 | setupWindow = tk.Tk() 146 | setupWindow.title("设置窗口") 147 | setupWindow.geometry('500x250') 148 | 149 | #调整分辨率按钮 150 | tk.Button(setupWindow, text='调整分辨率', command= changeResolution).grid(column=0, row=0) 151 | tk.Button(setupWindow, text='恢复分辨率', command= resetResolution).grid(column=1, row=0) 152 | 153 | #注册第一个选项相关组件 154 | lb1 = tk.Label(setupWindow, text=' 1.选择平台') 155 | lb1.grid(column=0, row=1, sticky=tk.W) 156 | global classChoice 157 | classChoice = tk.StringVar() 158 | classChoice.set('智慧树') 159 | rad1_1 = tk.Radiobutton(setupWindow, width=20, text='超星尔雅', variable= classChoice, value='超星尔雅', command=displayOption) 160 | rad1_2 = tk.Radiobutton(setupWindow, text='智慧树(Experimental)', variable= classChoice, value='智慧树', command=undisplayOption) 161 | rad1_1.grid(column=0, row=2, sticky=tk.W) 162 | rad1_2.grid(column=1, row=2, sticky=tk.W) 163 | 164 | #注册第二个选项相关组件 165 | global lb2, rad2_1, rad2_2, isQuestion 166 | lb2 = tk.Label(setupWindow, text=' 2.选择小节后是否有题目') 167 | isQuestion = tk.IntVar() 168 | isQuestion.set(0) 169 | rad2_1 = tk.Radiobutton(setupWindow, width=20, text='有题目', variable= isQuestion, value=1) 170 | rad2_2 = tk.Radiobutton(setupWindow, text='无题目', variable= isQuestion, value=0) 171 | 172 | #注册第三个选项相关组件 173 | selected_number = tk.StringVar() 174 | natural_numbers = [str(i) for i in range(1, 5)] 175 | selected_number.set(natural_numbers[0]) 176 | tk.Label(setupWindow, text='3.选择PngsGroup').grid(column=0, row=5, sticky=tk.W) 177 | option_menu = tk.OptionMenu(setupWindow, selected_number, *natural_numbers) 178 | option_menu.grid(column=1, row=5) 179 | 180 | 181 | def closeSetupGui(): 182 | #确定按钮的回调函数 183 | global pngsLocation 184 | pngsLocation = pngsGroupLocation + selected_number.get() 185 | #关闭窗口 186 | setupWindow.quit() 187 | setupWindow.destroy() 188 | 189 | 190 | #注册确认按钮组件 191 | btn = tk.Button(setupWindow, text='确认', command=closeSetupGui) 192 | btn.grid(column=3, row=6) 193 | 194 | setupWindow.protocol("WM_DELETE_WINDOW", exitProgram)#注册手动关闭窗口回调函数 195 | setupWindow.mainloop() 196 | 197 | 198 | """ 199 | 以下为超星尔雅的函数 200 | """ 201 | 202 | def cx_skipQuestion(): 203 | try: 204 | optionsLocation = list(pag.locateAllOnScreen(pngsLocation + r'\Options.png', confidence=0.9)) 205 | mouseMove(optionsLocation[0]) 206 | submitLocation = qLocate('Submit') 207 | mouseMove(submitLocation) 208 | for i in range(1,4): 209 | time.sleep(1) 210 | tempLocation = qLocate('NotCorrect') 211 | if not tempLocation is None: 212 | mouseMove(optionsLocation[i]) 213 | mouseMove(submitLocation) 214 | else: 215 | break 216 | except pag.ImageNotFoundException: 217 | return 218 | 219 | def cx_getVideoLocation(tempLocation ) -> list[int]: 220 | """ 221 | 获取视频播放位置,返回视频四角坐标 222 | """ 223 | screenshot = pag.screenshot() 224 | point_x, point_y = pag.center(tempLocation) 225 | 226 | backgoround_color = screenshot[point_x + 200, point_y] 227 | 228 | row_blank_witdh = 200 229 | col_blank_witdh = 100 230 | isBlank_y = point_y 231 | while True: 232 | isBlank = True 233 | for i in range(point_x + 200 - int(row_blank_witdh/2), point_x + 200 + int(col_blank_witdh/2)): 234 | if(screenshot[i, isBlank_y] != backgoround_color): 235 | isBlank = False 236 | break 237 | if (isBlank == False): 238 | videoLocation_top = isBlank_y + 1 239 | break 240 | else: 241 | isBlank_y += 1 242 | 243 | isBlank_y += 200 244 | 245 | blank_count = 0 246 | while True: 247 | isBlank = True 248 | for i in range(point_x + 200 - int(row_blank_witdh/2), point_x + 200 + int(col_blank_witdh/2)): 249 | if(screenshot[i, isBlank_y] != backgoround_color): 250 | isBlank = False 251 | break 252 | if (isBlank == True): 253 | blank_count += 1 254 | else: 255 | blank_count = 0 256 | 257 | if(blank_count == 10): 258 | videoLocation_bottom = isBlank_y - 10 259 | break 260 | 261 | isBlank_y += 1 262 | 263 | isBlank_x = point_x + 200 264 | isBlank_y = int((videoLocation_top + videoLocation_bottom)/2) 265 | 266 | blank_count = 0 267 | while True: 268 | isBlank = True 269 | for i in range(isBlank_y - int(col_blank_witdh/2), isBlank_y + int(col_blank_witdh/2)): 270 | if(screenshot[isBlank_x, i] != backgoround_color): 271 | isBlank = False 272 | break 273 | 274 | if(isBlank == False): 275 | blank_count += 1 276 | else: 277 | blank_count = 0 278 | 279 | if(blank_count == 10): 280 | videoLocation_left = isBlank_x + 10 281 | break 282 | isBlank_x -= 1 283 | 284 | isBlank_x = point_x + 200 285 | blank_count = 0 286 | while True: 287 | isBlank = True 288 | for i in range(isBlank_y - int(col_blank_witdh/2), isBlank_y + int(col_blank_witdh/2)): 289 | if(screenshot[isBlank_x, i] != backgoround_color): 290 | isBlank = False 291 | break 292 | 293 | if(isBlank == False): 294 | blank_count += 1 295 | else: 296 | blank_count = 0 297 | 298 | if(blank_count == 10): 299 | videoLocation_right = isBlank_x + 10 300 | break 301 | isBlank_x += 1 302 | 303 | return [videoLocation_top, videoLocation_bottom, videoLocation_left, videoLocation_right] 304 | 305 | 306 | def cx_playVideo(): 307 | """ 308 | 播放视频,包含弹出题目处理 309 | """ 310 | tempLocation = qLocate("cx_point",0.95) 311 | print("find point") 312 | print(tempLocation) 313 | 314 | # 找到视频位置并开始播放 315 | videoLocation = cx_getVideoLocation(tempLocation) 316 | pag.moveTo(int((videoLocation[0] + videoLocation[1])/2), int((videoLocation[2] + videoLocation[3])/2)) 317 | time.sleep(0.1) 318 | pag.leftClick() 319 | 320 | screenPic = pag.screenshot() 321 | videoLocation = screenPic[videoLocation[0]:videoLocation[1], videoLocation[2]:videoLocation[3]] 322 | 323 | while True: 324 | time.sleep(5) 325 | videoCapture_last = videoCapture 326 | videoCapture = screenPic[videoLocation[0]:videoLocation[1], videoLocation[2]:videoLocation[3]] 327 | 328 | # 检测视频是否开始播放 329 | difference = cv2.subtract(videoCapture, videoCapture_last) 330 | result = not cv2.countNonZero(difference) 331 | if (result != True): 332 | continue 333 | 334 | freezedCount = 0 335 | waitCount = 0 336 | while True: 337 | time.sleep(10) 338 | videoCapture_last = videoCapture 339 | videoCapture = screenPic[videoLocation[0]:videoLocation[1], videoLocation[2]:videoLocation[3]] 340 | difference = cv2.subtract(videoCapture, videoCapture_last) 341 | result = not cv2.countNonZero(difference) 342 | if(result != True): 343 | tempLocation = qLocate("Submit") 344 | if not tempLocation is None: 345 | cx_skipQuestion() 346 | else: 347 | freezedCount += 1 348 | 349 | if(freezedCount == 10 or waitCount == 240): 350 | return 351 | 352 | 353 | 354 | 355 | 356 | 357 | # mouseMove(tempLocation, 375, 355) #偏移了播放键相对于任务点的位置 358 | # time.sleep(1) 359 | # pag.move(0, -20, 0.5, pag.easeOutQuad) 360 | # pag.move(0, 20, 0.5, pag.easeOutQuad) 361 | 362 | # 利用重播键判定视频是否播放完毕 363 | # tempLocation = qLocate("Pause") 364 | # if not tempLocation is None: 365 | # try: 366 | # print(pngsLocation + r'\Replay.png') 367 | # tempLocation = pag.locateAllOnScreen(pngsLocation + r'\Replay.png',confidence=0.9) 368 | # replayCountBefore = len(list(tempLocation)) 369 | # except: 370 | # replayCountBefore = 0 371 | 372 | # time.sleep(5) 373 | # waitCount = 0 374 | # while (1): 375 | # tempLocation = qLocate("Submit") 376 | # if not tempLocation is None: 377 | # cx_skipQuestion() 378 | # time.sleep(10) 379 | # waitCount += 1 380 | # print(waitCount) 381 | # if(waitCount >=240): 382 | # break 383 | # try: 384 | # tempLocation = pag.locateAllOnScreen(pngsLocation + r'\Replay.png',confidence=0.9) 385 | # replayCountAfter = len(list(tempLocation)) 386 | # except: 387 | # replayCountAfter = 0 388 | # if(replayCountBefore != replayCountAfter): 389 | # break 390 | 391 | 392 | 393 | 394 | def cx_startChapter(): 395 | """ 396 | 开始一个小节的播放 397 | """ 398 | pag.moveTo(1750,730) 399 | searchCoumt = 0 400 | while (searchCoumt<=30): 401 | tempLocation = qLocate("cx_point",0.96) 402 | if not tempLocation is None: 403 | print("findpoint") 404 | print(tempLocation) 405 | x1, y1 = pag.center(tempLocation) 406 | while(y1>=270): 407 | pag.scroll(-80) 408 | time.sleep(0.1) 409 | try: 410 | x1, y1 = pag.center(qLocate("cx_point",0.96)) 411 | except: 412 | None 413 | cx_playVideo() 414 | searchCoumt = 0 415 | else: 416 | pag.scroll(-50) 417 | time.sleep(0.04) 418 | searchCoumt += 1 419 | 420 | def cx_locateNextChapter(isQuestion:bool): 421 | """ 422 | 判断处理小节后问题以及小节目录的滚动 423 | :param isQuestion: 用户选择的章节后是否有题目 424 | """ 425 | pag.moveTo(2300,700) 426 | locateCount = 0 427 | while(locateCount<=15): 428 | if(isQuestion): 429 | tempLocate = cx_locateChapterPosition(2) 430 | else: 431 | tempLocate = cx_locateChapterPosition(1) 432 | if not tempLocate is None: 433 | pag.moveTo(tempLocate[0]-250, tempLocate[1])#200为点击位置相对剩余视频数标识 434 | time.sleep(0.5) 435 | pag.click() 436 | time.sleep(3) 437 | return 438 | else: 439 | pag.scroll(-50) 440 | time.sleep(0.3) 441 | pag.press("F5") 442 | 443 | 444 | def cx_locateChapterPosition(startNum:int): 445 | """ 446 | 在一个固定界面寻找下一个小节的位置,依靠未播放的视频数判断。 447 | 448 | :param startNum: 搜索起始的剩余视频数 449 | :return: 最靠上的未完成的小节的位置,以列表形式返回。若没有找到任何符合条件的小节,返回None 450 | """ 451 | locationX = [] 452 | locationY = [] 453 | for i in range(startNum, 8): 454 | filePath = ''+str(i) 455 | tempLocation = qLocate(filePath) 456 | if not tempLocation is None: 457 | x1, y1 = pag.center(tempLocation) 458 | locationX.append(x1) 459 | locationY.append(y1) 460 | if len(locationX) == 0: 461 | return None 462 | else: 463 | return [locationX[locationY.index(min(locationY))], min(locationY)] 464 | 465 | 466 | 467 | """ 468 | 以下为智慧树平台函数 469 | """ 470 | 471 | def zh_skipQuesion(): 472 | """ 473 | 跳过视频中间弹出的问题 474 | """ 475 | tempLocation = qLocate('zh_optionA') 476 | if not tempLocation is None: 477 | mouseMove(tempLocation) 478 | else: 479 | tempLocation = qLocate('zh_optionB') 480 | mouseMove(tempLocation) 481 | tempLocation = qLocate('zh_closeQuestion') 482 | if not tempLocation is None: 483 | mouseMove(tempLocation) 484 | 485 | 486 | 487 | """ 488 | 以下为主函数 489 | """ 490 | 491 | width, height = pag.size() 492 | 493 | displaySetupGui() 494 | 495 | time.sleep(5) 496 | while (1): 497 | #超星尔雅平台 498 | if(classChoice.get() == '超星尔雅'): 499 | #开始播放小节 500 | cx_startChapter() 501 | #寻找下一小节 502 | print("Find next stage") 503 | cx_locateNextChapter(isQuestion.get()) 504 | 505 | 506 | #智慧树平台 507 | else: 508 | time.sleep(5) 509 | tempLocation = qLocate('zh_caution') 510 | if not tempLocation is None: 511 | mouseMove('zh_skipCaution') 512 | while(1): 513 | #开始播放 514 | pag.moveTo(900, 1000, 0.5, pag.easeInQuad) 515 | time.sleep(0.5) 516 | pag.click() 517 | #等待播放结束 518 | pag.move(0, -15, 0.5, pag.easeInQuad) 519 | time.sleep(0.1) 520 | pag.move(0, 15, 0.5, pag.easeInQuad) 521 | tempLocation = qLocate('zh_finished') 522 | counter = 0 523 | while (counter<=360 and tempLocation is None): 524 | print("wait") 525 | time.sleep(7) 526 | pag.moveTo(900, 1000, 0.5, pag.easeInQuad) 527 | pag.move(0, -15, 0.5, pag.easeInQuad) 528 | time.sleep(0.1) 529 | pag.move(0, 15, 0.5, pag.easeInQuad) 530 | #答题 531 | tempLocation = qLocate('zh_question') 532 | if not tempLocation is None: 533 | zh_skipQuesion() 534 | time.sleep(1) 535 | pag.click() 536 | counter = counter+1 537 | tempLocation = qLocate('zh_finished') 538 | 539 | #寻找下一节 540 | pag.moveTo(2200,900) 541 | pag.scroll(-50) 542 | time.sleep(1) 543 | isFound = False 544 | for i in range(10): 545 | try: 546 | allUnplay = pag.locateAllOnScreen(pngsLocation + r'\zh_unplay.png', confidence=0.9) 547 | except: 548 | allUnplay = None 549 | for everyUnplay in allUnplay: 550 | listUnplay = list(everyUnplay) 551 | try: 552 | tempLocation = pag.locateOnScreen(pngsLocation + r'\zh_played.png', region=(listUnplay[0]+250, listUnplay[1]-30, 60, 60), confidence=0.9) 553 | except: 554 | tempLocation = None 555 | print(listUnplay[0]+250, listUnplay[1]-30) 556 | print(tempLocation) 557 | if tempLocation is None: 558 | mouseMove(everyUnplay) 559 | time.sleep(5) 560 | isFound = True 561 | break 562 | if isFound == False: 563 | pag.scroll(-height//3) 564 | time.sleep(1) 565 | else: 566 | break 567 | -------------------------------------------------------------------------------- /codes/ChangeRes.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | try: 3 | from win32 import win32api, win32gui, win32print 4 | import win32con 5 | import pywintypes 6 | import os 7 | except ImportError: 8 | print('安装依赖库') 9 | subprocess.call(['pip','install','pywin32']) 10 | 11 | cwd, temp=os.path.split(os.path.abspath(__file__)) 12 | #获取用户分辨率和缩放 13 | 14 | sX = win32api.GetSystemMetrics(0) #获得屏幕分辨率X轴 15 | sY = win32api.GetSystemMetrics(1) #获得屏幕分辨率Y轴 16 | #获取缩放前分辨率 17 | hDC = win32gui.GetDC(0) 18 | userWidth = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES) # 横向分辨率 19 | userHeight = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES) # 纵向分辨率 20 | print(userHeight, sY) 21 | userScale = int(100 * round( userHeight/ sY, 2)) 22 | 23 | #保存用户设置 24 | 25 | userFile = open(cwd + r'\UserFile.txt', 'r') 26 | 27 | #检测配置状态,保存的不是用户初始分辨率的情况下保存显示设置 28 | if(userFile.readline() != 'UserConfig\n'): 29 | userFile = open(cwd + r'\UserFile.txt', 'w') 30 | #保存原始显示设置 31 | userFile.writelines(['UserConfig','\nWidth = \n', str(userWidth),'\nHeight = \n',str(userHeight),'\nScale = \n',str(userScale)]) 32 | print("Write") 33 | userFile.close() 34 | 35 | #更改分辨率 36 | devmode = pywintypes.DEVMODEType() 37 | 38 | devmode.PelsWidth = 2560 39 | devmode.PelsHeight = 1440 40 | 41 | devmode.Fields = win32con.DM_PELSWIDTH | win32con.DM_PELSHEIGHT 42 | 43 | win32api.ChangeDisplaySettings(devmode, 0) 44 | 45 | #更改缩放 46 | win32api.ShellExecute(0, 'open', cwd+'\SetDpi.exe', ' 125', '', 0) -------------------------------------------------------------------------------- /codes/ResetRes.py: -------------------------------------------------------------------------------- 1 | 2 | ########################## 3 | #已集成到主程序中,暂时废弃# 4 | ########################## 5 | 6 | import subprocess 7 | try: 8 | from win32 import win32api, win32gui, win32print 9 | import win32con 10 | import pywintypes 11 | import os 12 | except ImportError: 13 | print('安装依赖库') 14 | subprocess.call(['pip','install','pywin32']) 15 | 16 | cwd = os.path.abspath(os.path.dirname(__file__)) 17 | 18 | try: 19 | with open(cwd + r'\UserFile.txt', 'r') as userFile: 20 | fileInput = userFile.readlines() 21 | userWidth = int(fileInput[2]) 22 | userHeight = int(fileInput[4]) 23 | userScale = int(fileInput[6]) 24 | except Exception as e: 25 | print("无法处理配置文件,删除\"UserFile.txt\"后重试") 26 | print("读取的文件为:",fileInput) 27 | print("获取的异常为", e) 28 | quit() 29 | 30 | 31 | userFile = open(cwd + r'\UserFile.txt', 'w') 32 | userFile.writelines(['Resolution has been reset once.\n', 'Manually configuring your resolution and scale ratio if any problem.']) 33 | # userFile.writelines(['notOriginal','\n', str(userWidth),'\n',str(userHeight),'\n',str(userScale)]) 34 | userFile.close() 35 | 36 | #更改分辨率 37 | devmode = pywintypes.DEVMODEType() 38 | 39 | devmode.PelsWidth = userWidth 40 | devmode.PelsHeight = userHeight 41 | 42 | devmode.Fields = win32con.DM_PELSWIDTH | win32con.DM_PELSHEIGHT 43 | 44 | win32api.ChangeDisplaySettings(devmode, 0) 45 | 46 | #更改缩放 47 | win32api.ShellExecute(0, 'open', cwd+'\SetDpi.exe', ' '+str(userScale), '', 0) -------------------------------------------------------------------------------- /codes/SetDpi.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spp901780/AutoOnlineClass/c6eaca091c6aba55679e3784e48b9e08e1e9919e/codes/SetDpi.exe -------------------------------------------------------------------------------- /codes/UserFile.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /codes/test.py: -------------------------------------------------------------------------------- 1 | import easyocr 2 | import cv2 3 | import pyautogui as pag 4 | import time 5 | import numpy as np 6 | def recognize_digits_with_coordinates_from_array(image_array): 7 | # 创建 easyocr Reader 对象 8 | reader = easyocr.Reader(['en']) # 这里指定语言为英文 9 | 10 | # 读取并识别图像中的文本 11 | results = reader.readtext(image_array, gpu=True) 12 | 13 | # 过滤出数字及其坐标 14 | digits_with_coordinates = [] 15 | for (bbox, text, prob) in results: 16 | if text.isdigit(): 17 | digits_with_coordinates.append((text, bbox)) 18 | 19 | return digits_with_coordinates 20 | 21 | time.sleep(2) 22 | screen = pag.screenshot() 23 | screen_np = np.array(screen) 24 | screen_cv2 = cv2.cvtColor(screen_np, cv2.COLOR_RGB2BGR) 25 | cv2.imshow('screen', screen_cv2) 26 | recognized_digits = recognize_digits_with_coordinates_from_array(screen_np[2000:2559, 200:1380]) 27 | for digit, bbox in recognized_digits: 28 | print(f"Recognized digit: {digit}, Coordinates: {bbox}") -------------------------------------------------------------------------------- /恢复分辨率.bat: -------------------------------------------------------------------------------- 1 | python .\codes\ResetRes.py --------------------------------------------------------------------------------