From b1285b5d8ed893fa7d1e57d74d6e06c6a73fb8d3 Mon Sep 17 00:00:00 2001 From: JesterHey Date: Wed, 13 Mar 2024 22:30:35 +0800 Subject: [PATCH] new file: __pycache__/get_in.cpython-310.pyc modified: __pycache__/get_info.cpython-310.pyc new file: __pycache__/initialization.cpython-310.pyc modified: __pycache__/kill_course.cpython-310.pyc modified: __pycache__/single_course.cpython-310.pyc modified: course_info.json modified: demo.py deleted: file.log new file: get_in.py modified: get_info.py new file: info.json modified: initialization.py modified: kill_course.py deleted: kill_quiz.py modified: main.py modified: single_course.py --- __pycache__/get_in.cpython-310.pyc | Bin 0 -> 1907 bytes __pycache__/get_info.cpython-310.pyc | Bin 2618 -> 2884 bytes __pycache__/initialization.cpython-310.pyc | Bin 0 -> 4540 bytes __pycache__/kill_course.cpython-310.pyc | Bin 1304 -> 1304 bytes __pycache__/single_course.cpython-310.pyc | Bin 2689 -> 2727 bytes course_info.json | 2 +- demo.py | 30 ++---- file.log | 1 - get_in.py | 70 ++++++++++++++ get_info.py | 66 +++++++++----- info.json | 1 + initialization.py | 101 ++++++++++++++++++--- kill_course.py | 15 +-- kill_quiz.py | 5 - main.py | 51 +++++++---- single_course.py | 30 +++--- 16 files changed, 271 insertions(+), 101 deletions(-) create mode 100644 __pycache__/get_in.cpython-310.pyc create mode 100644 __pycache__/initialization.cpython-310.pyc delete mode 100644 file.log create mode 100644 get_in.py create mode 100644 info.json delete mode 100644 kill_quiz.py diff --git a/__pycache__/get_in.cpython-310.pyc b/__pycache__/get_in.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..081c6af43e369f41d9ceecbbf9e4270d06f996d7 GIT binary patch literal 1907 zcmZuxTW=Fb6rS7KYiAvj5H2OOqOJO1Dn%uIsSu*5s8TCc2#Kn+E2P!NGjTStcdglR z9HX@a4G>2tkV?ICX@a^9-)xY} zWf6RruKguM2BAN-^72POIRZUA2!bPyOUTABk`gKto8X>}+LTky&LNu#gB$ZiP6)Py z0L3Sgo=Yz#sEIoNGaG{h$$k`-C7es3=l+{y5UE)hC`@~vep9eMX zOQ^oL1{LXQ8pL?<1%5ZrsyjgG{P9ia$<_Av%k3X8wVwXaKKJzbne$Z(kk*wOt$Vjy zj~;ZFeyvVu!_7Nj=zRN2>*-Qw?LzD9t=8j*?eBhi{`G_En8wfFYMuYNbLW2h`q@_V zLhIgIV(y+=pMaJxEIp2SRvMHRD|z*l+F)nx7( z8o@TJxV+xo21;y7;qt&Q)$=q?Ex4ts2xFt>aWxwop@Jjli6$QEj)SPCKs^8bcI)y( zFzX!?0kJF{Yr&PCJ6#ge1f=gLHGdPo*8K~e^|LYFpQmzEyXsXj3ulAcE2L*&*3fq7 zp#;%n>u4h(egid$o&()cGLnci@dB3Px>O3D1Sd=6@)*z`o%X=JE~q0`BY4cLd8b4QV}v{K}Gm6OWYZ+mMeCei%`j+o@Y|CMDEmL7l;_o+%;^Y z5R|8bI2}}!7x#SeN*pEy+1iMc>oLr zZ8$E2IZ;sIsY2cLo!LN!;uPfPc>ZLi9_Pa9blFpmThP&_Ad7Gh2n(A@V_44!W}5`3 zHur8?^z{A$5Jd^66cjz*sU@#q@=z%#xTWy$V$AF{OZ_ly^QgYo>0r?|KKAwM)JIjN0^c^vuIHD6ppwtoR_{1) zDxkfc>ubGew$)2#3+!us&@2e}HArXC-kR0zp`?;dNvC2D4@&lL9ULK@;X#@E_&`r^ z`L;g9R<)*+)a9G{2H())EfDec|EY|Ar{NJ0Cdpz(SyI(;JdXEalR}N@2(|DSv9KN) zNkNq@G6FgyW-=eABSRLpsNAnZn2w{b%W;6^X*Cb`FQj}2kmQo3{*?_D>L=njy(E)N d6Om+U9x4aCS`vpbIE2F>%pT>a`5~ma`8UmNA{YPw literal 0 HcmV?d00001 diff --git a/__pycache__/get_info.cpython-310.pyc b/__pycache__/get_info.cpython-310.pyc index 0fb95b6a8d5e1a871acf061cf15fa10ca3e9582f..c0e769198375ac8580014636f52736c56b9e76c3 100644 GIT binary patch delta 1901 zcmZ8h&2Jk;6rY)$UGJ{f>(8W3X-hu@$SS05_>xMC3W3}R5iP1}ij3=-Bo4OMogEWm z)-uTL3AI&a331?H_W~TC;)Xzi3y2GU!AeLV3N##$xc1QSW*nEOGnzN^KIZGa-+SK_ zewaQIq*5+|cKfS;`KuX(epk%S<^XdVM)>88BTGHR%zConl{}1?#qly>31(lWr4%c$ zB=?yIBgNCq=jmmerCH{(S<0{}r32e6%K@L|IhKE$h}XH-M;P&}qRcp>M{#;n-CiWI zH@_-^My=ggs;uxht+^Y&?%7qualR^eMe=ezSgAG3>$N5e)^FVH_Y$!4b0pM}pmTJT_YEtg4JBEiu4kpGiB} zhz<^uc}xc@>puS)~(jKF&l zU2}&?rcdcS3>;<|MwoGxi1+o*%*3+kYi;(KZS^&+&Q8?lP;)m$l5Tv8;aH3$8Coo- zE|lId#qxt!jEC~H4?IHw#bcMz3Id@Hc%HJA*^! zQ$6LnVnU=~622nJvjSj;V%mZ*3mcZDM6KDX28`=Kj!9CPm^$7CScb0wp_pQe5bR?Y zTbSPS3?Gv%3K9#tyX6tZyVNBa;*kvY$>1k*U+*`%Upxxis~E_nsVAtr=V62&gGQo0 z>f(+o@sLP^VMhAk-7WzK6|{p6Zac_S=zY-YJZj=~6hQ=LP}hK&!c3(VA=Wb^BcjZ@ zN?}`KXtRV4CkkJTwu8Atiq~9bGl#iX$uOw`T|-?{M*^UOk%M55%K#z(5Nqf&07y3x zC0;^r9_iYVy_Ozk7=WbfL=MZq6Wqw@F%K3=5F}vsWENJ=41|(puaFtk$K4c2a-j30 zWaLGu$Y=RaXk*;P9oHqr>r$zudZgy749hpReCgsRKJR7NJ_7uzc_<#is4{eyG%V{fr`qgBj|^Xw62IHSn_ z$(F1JZ76!W;FT=>zc4nW2xB5e$*#7AR>jW5j+G``^iK!B*pK&Ancb0{_N0Qo0P=7N zh)T`^_8=JxnB21s8)t}1D7GPCbC?nr6YPS-1{+)Vf})1EMId#3kWxrs@=u|lQu)x9 zSb#%gyIgKmpzM3)B0amXxLCwzi}^vvd9L@gdeEG*v7l14MO*tv9MlqsO|7{STjN)b zeXPn+OfLpOJvKrqw9oHfqCQ$K@2Elgzq%0FCmR84*ZK1b2;l)B8D!(V<3Ei5;$h#~ OYi6FXk3uPe;`ATEV#;9v delta 1494 zcmYjR&2Jk;6yKShU9b1cj%@-_8a`U7$fS{-kTe8Z6saM=fhwp$1xuB+@r>7OF)(aabSWA3);3iNArv9yq{-a^lQ^@Mc3oX7t|7`31QV9|{PYK*2Xp7k55X7;0mx(%eJRFz5``nMn<1wh1+<^-yV8 zv?O%kW77i2HY?ELUCcjV_C!Jwm2YKKEkFJBYP^Uh8!BA=oy7C7{JmcLBw#$K-5=d| z9l!5*wVi`j*WrU5?)O+L3~H?d$7^D1G+ zGi%xY&-^4am*cLyU{u8M&`d1)Lj1KnU&a%V#RE>MIvf8aKS9O#BT`#zl-8D)SL-V) z_4*pj^^N-Sr-%7VLnjFC`J6WNuD3r}UU_qM?P~lbd4zJYrK}?@eot9-L@KKa7y0ED zu#^m)4&yo4Hgc{vZ26RBMLS^vLaEaCJFZuNZEzD9K?JE7BOB>RMdTk-wh=xipqWJ` zivLiSj(#Hx{1UjfpcZEXK=^-^-Udrn9TcKS63-2BB2$!QSPEW@P(nn0&uLLl5vil( zF-}xrbD_3W8OvcV(WsiGFdxYiv~?uic^?Xg5{2fV&`P8vI@MsOM(UPy=khog<$6Y9 z(md$2NTd3kG|t0{VAVqlcJdtLo*Iwv90WHuK%;=ojEqQ+Olp2BM>xt~llI?2|wO8X!ZDGDD zr-VBpOG$VzWT_g2PB;p93Ebi@wAZA&Hybj#T`Yhn{aXtTf(;qS~CB480PDg`b)jomQML5gCM}79L=$YU`{F+fVZBmhoZ)lfwM2`OjK~Psc diff --git a/__pycache__/initialization.cpython-310.pyc b/__pycache__/initialization.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7e6c6dea78fdb8291e5bd855c2fcab158110563 GIT binary patch literal 4540 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 -# elif page.ele('tag:img@@style=width: 25px;height: 25px;',timeout=3): -# page.ele('tag:img@@style=width: 25px;height: 25px;').click() -# except BaseException: -# logger.error('不能进入课程页面') -# subprocess.run(["python", __file__]) -# exit() -# page.ele('tag:a@@text():青马课堂').hover() -# page.ele('tag:a@@text():全部').click().for_new_tab() -login(first=True,init=True) \ No newline at end of file +import json +dic = json.load(open('course_info.json', 'r')) +l1 = [ i for i in dic.keys() if dic[i]['type'] == '选修' ] +l2 = [ i for i in dic.keys() if dic[i]['type'] == '必修' ] +l3 = [ i for i in dic.keys() if dic[i]['type'] == '专题' ] +l4 = [ i for i in dic.keys() if dic[i]['type'] == '培训' ] +print(len(l1)) +print(len(l2)) +print(len(l3)) +print(len(l4)) \ No newline at end of file diff --git a/file.log b/file.log deleted file mode 100644 index bb1db5f..0000000 --- a/file.log +++ /dev/null @@ -1 +0,0 @@ -2024-03-10T12:13:35.955107+0800 DEBUG 这是一条具有自定义格式的日志信息 diff --git a/get_in.py b/get_in.py new file mode 100644 index 0000000..da919f6 --- /dev/null +++ b/get_in.py @@ -0,0 +1,70 @@ +import tkinter as tk +from tkinter import ttk +import json + + +def create_login_window(): + # 创建主窗口 + root = tk.Tk() + root.title("Integrated Window") + + # 设置窗口的初始大小并居中显示 + window_width = 600 + window_height = 400 + screen_width = root.winfo_screenwidth() + screen_height = root.winfo_screenheight() + center_x = int(screen_width / 2 - window_width / 2) + center_y = int(screen_height / 2 - window_height / 2) + root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}") + + # 用户名和密码变量 + username_var = tk.StringVar() + password_var = tk.StringVar() + + # 下拉选择框的选项 + options = ['网络文明志愿者', '团学干部', '大学生心理健康教育', '入党积极分子'] + + # 创建下拉选择框 + combo_label = tk.Label(root, text="选择学习类型", font=('Helvetica', 12)) + combo_label.pack(pady=(10, 5)) + + combo = ttk.Combobox(root, values=options, width=15, state="readonly") + combo.pack(pady=(0, 20)) # pady增加垂直外边距,有助于在窗口中垂直居中 + + # 创建用户名和密码的标签和输入框 + username_label = tk.Label(root, text="账号", font=('Helvetica', 12)) + username_label.pack(pady=(5, 5)) + + username_entry = tk.Entry( + root, textvariable=username_var, font=('Helvetica', 12)) + username_entry.pack(pady=(0, 10)) + + password_label = tk.Label(root, text="密码", font=('Helvetica', 12)) + password_label.pack(pady=(5, 5)) + + password_entry = tk.Entry( + root, textvariable=password_var, font=('Helvetica', 12), show="*") + password_entry.pack(pady=(0, 20)) + + # 确定按钮的事件处理函数 + def submit_action(): + username = username_var.get().upper() + password = password_var.get() + study_type = combo.get() + if study_type not in options: + return + with open('info.json', 'w') as f: + json.dump({'username': username, 'password': password, + 'study_type': study_type}, f) + root.destroy() + + submit_button = tk.Button(root, text="提交", command=submit_action) + submit_button.pack(pady=(10, 0)) + + # 运行主循环 + root.mainloop() + + +# 调用函数以创建和显示登录窗口 +if __name__ == "__main__": + create_login_window() diff --git a/get_info.py b/get_info.py index 96fdd42..6b0ff96 100644 --- a/get_info.py +++ b/get_info.py @@ -1,4 +1,4 @@ -from DrissionPage import ChromiumPage,ChromiumOptions +from DrissionPage import ChromiumPage, ChromiumOptions from DrissionPage.common import * from collections import * import time @@ -6,47 +6,53 @@ import json from loguru import logger import subprocess from typing import * +from get_in import create_login_window # http://hnqmgc.17el.cn/grzx/ # 单独实现登录操作 -def get_into_center(cpage:ChromiumPage): - cpage.ele('#login_btn').click() - cpage.ele('@value=进入个人中心').click() -def login(first:bool=True,init:bool=False): + + +def get_into_center(cpage: ChromiumPage): + cpage.ele('#login_btn').click() + cpage.ele('@value=进入个人中心').click() + + +def login(first: bool = True, init: bool = False, username: str = None, pwd: str = None): if not first: return # 先检查当前页面是否已经登录 page = ChromiumPage() try: - if page.ele('tag:div@@text():欢迎您,',timeout=3): + if page.ele('tag:div@@text():欢迎您,', timeout=3): logger.info('当前页面已登录') return except BaseException: logger.info('准备登录') if first: try: - page.get('http://hnqmgc.17el.cn/grzx/',retry=5,timeout=5,interval=1) + page.get('http://hnqmgc.17el.cn/grzx/', + retry=5, timeout=5, interval=1) except BaseException: logger.error('网络连接失败') # 定位到账号文本框,获取文本框元素 - ele = page.ele('#userName') # #的意思是通过id定位元素 + ele = page.ele('#userName') # 的意思是通过id定位元素 # 输入对文本框输入账号 - ele.input('51140220050507901X') + ele.input(username) # 定位到密码文本框并输入密码 - page.ele('#password').input('hnqm123456') + page.ele('#password').input(pwd) # 定位到验证码文本框并输入验证码 - inpcode = page.ele('#yzcode').text # 湖南青马太可爱了吧,验证码居然直接放在页面源码里:) + inpcode = page.ele('#yzcode').text # 湖南青马太可爱了吧,验证码居然直接放在页面源码里:) page.ele('#inpcode').input(inpcode) # 点击登录按钮 page.ele('#btnLogin').click() page.wait.new_tab(3) # 进入课程页面 try: - if page.ele('@onclick=cha()',timeout=3): + if page.ele('@onclick=cha()', timeout=3): page.ele('@onclick=cha()').click() # - elif page.ele('tag:img@@style=width: 25px;height: 25px;',timeout=3): + elif page.ele('tag:img@@style=width: 25px;height: 25px;', timeout=3): page.ele('tag:img@@style=width: 25px;height: 25px;').click() except BaseException: logger.error('不能进入课程页面') @@ -54,24 +60,30 @@ def login(first:bool=True,init:bool=False): exit() if not init: get_into_center(page) -def get_info(first:bool=True): + + +def get_info(first: bool = True): # 创建页面对象,并启动或接管浏览器 page = ChromiumPage() + try: + info = json.load(open('info.json', 'r')) + except BaseException: + create_login_window() + info = json.load(open('info.json', 'r')) + username = info['username'] + pwd = info['password'] # 登录 - login(first) + login(first, init=False, username=username, pwd=pwd) # 提取课程信息 time.sleep(2) if not first: page.refresh() time.sleep(2) - page.ele('@value=0',timeout=3).click() + page.ele('@value=0', timeout=3).click() # 获取总页数 course_info = {} - #
1 / 4
- # total_page = int(page.ele('.paginationjs-nav J-paginationjs-nav').text) - total_page = 4 logger.debug('读取课程信息中...') - for i in range(total_page): + while 1: # 逐页读取课程信息和完成状态并存放到字典中 tbodys = page.ele('#tbody') # 获取tbody下的所有tr @@ -79,18 +91,24 @@ def get_info(first:bool=True): for tr in trs: cur_info = tr.text.split('\t') course_id = cur_info[0] # 课程id - course_type = cur_info[2] # 课程类型 + course_name = cur_info[1] # 课程名称 + course_type = cur_info[2] # 课程类型 course_rate = int(cur_info[3][:-1]) # 课程完成百分比 course_status = cur_info[4] # 课程完成状态(是否完成习题/评价) # 存放到字典中 - course_info[course_id] = {'rate': course_rate,'type': course_type,'status': course_status} - if i != total_page - 1: + course_info[course_id] = { + 'name': course_name, 'type': course_type, 'rate': course_rate, 'status': course_status} + try: page.ele('@title=Next page').click() time.sleep(1) + except BaseException: + break logger.success('课程信息读取完成,共有{}门课程'.format(len(course_info))) # 写入json文件中 with open('course_info.json', 'w') as f: json.dump(course_info, f) + if __name__ == '__main__': - get_info() \ No newline at end of file + create_login_window() + get_info() diff --git a/info.json b/info.json new file mode 100644 index 0000000..3e13eb7 --- /dev/null +++ b/info.json @@ -0,0 +1 @@ +{"username": "51140220050507901X", "password": "hnqm123456", "study_type": "\u7f51\u7edc\u6587\u660e\u5fd7\u613f\u8005"} \ No newline at end of file diff --git a/initialization.py b/initialization.py index 3e88721..bdeafd5 100644 --- a/initialization.py +++ b/initialization.py @@ -13,7 +13,8 @@ from get_info import get_info from collections import * from get_info import login -def click_videoes(study_type:str) -> None: + +def click_videoes(study_type: str, class_info: dict) -> None: ''' study_type:只能在如下选项中选择 1、入党积极分子 @@ -21,33 +22,100 @@ def click_videoes(study_type:str) -> None: 3、团学干部 4、大学生心理健康教育 ''' - # 由于各位学员的培训种类不同,这里交给用户输入 + click_page = ChromiumPage() # 接管当前页面 + valid_type = ['入党积极分子', '网络文明志愿者', '团学干部', '大学生心理健康教育'] + if study_type not in valid_type: + logger.critical('study_type参数错误! 请检查后重新输入!') + return + must = [class_info[k]['name'] + for k in class_info.keys() if class_info[k]['type'] == '必修'] + elective = [class_info[k]['name'] + for k in class_info.keys() if class_info[k]['type'] == '选修'] + column = [class_info[k]['name'] + for k in class_info.keys() if class_info[k]['type'] == '专题'] + # 去空格 + must = [i.strip() for i in must] + elective = [i.strip() for i in elective] + column = [i.strip() for i in column] + # 处理不同的身份用户的个性化专栏 - # 必修,选修,专栏学习是每人都要学习的,统一处理 - def must_study(): - pass - def elective_study(): + def go_special_page(study_type: str) -> None: + click_page.ele(f'tag:a@@text():{study_type}').click() + time.sleep(1) + kcs = click_page.eles('.kclist') + for kc in kcs: + kc_name = kc.ele('.kcmc').text.strip() + if kc_name in column: + continue + else: + kc.ele('.xx').click() + time.sleep(1) + click_page.wait.new_tab(timeout=3) + tab = click_page.latest_tab + try: + tab.ele('tag:input@@text():继续学习').click() + except BaseException: + pass + time.sleep(5) + click_page.close_tabs([tab]) + time.sleep(5) pass - def column_study(): - pass - + # 所有用户都需要进入的视频 + def go_video_page(course_type: str) -> None: + if len(must) >= 10 and len(elective) >= 10 and len(column) >= 10: + return + if course_type == '专题': + course_type = '专栏学习' + dic = {'必修': must, '选修': elective, '专栏学习': column} + # 进入视频一次页 + click_page.ele(f'tag:a@@text():{course_type}').click() + time.sleep(1) + kcs = click_page.eles('.kclist') + for kc in kcs: + kc_name = kc.ele('.kcmc').text.strip() # 空格太抽象了 :) + if kc_name in dic[course_type]: + continue + else: + kc.ele('.xx').click() + click_page.wait.new_tab(timeout=3) + time.sleep(1) + tab = click_page.latest_tab + try: + tab.ele('tag:a@@text():继续学习').click() + except BaseException: + pass + time.sleep(5) + click_page.close_tabs([tab]) + time.sleep(5) + if len(must) < 10: + go_video_page('必修') + if len(elective) < 10: + go_video_page('选修') + if len(column) < 10: + go_video_page('专题') + go_special_page(study_type) # 读取课程数量信息 -def init(): + + +def init(study_type: str = '网络文明志愿者'): ''' 初始化,检测是否需要进入视频一次页以及进行进入视频一次操作 ''' # 获取课程数量信息 get_info() - class_info = json.load(open('course_info.json','r')) + class_info = json.load(open('course_info.json', 'r')) # 读取各个类别的课程数量 cnt = Counter(class_info[k]['type'] for k in class_info.keys()) # 检测是否存在小于10的课程数量 less_10 = [k for k, v in cnt.items() if v < 10] if not less_10: # 直接进行刷课和检测 + logger.info('所有课程数量均大于10,无需初始化') return else: + logger.debug(f'存在课程数量小于10的课程类型:{less_10}') + logger.debug('正在进行初始化...') ''' 回到首页,逐个点击相应视频,每个视频页面停留3秒后推出,并进入下一个视频。 结束调用get_info()函数,更新课程数量信息 @@ -55,8 +123,11 @@ def init(): # 接管当前页面 page = ChromiumPage() # 进入青马课堂页 - login(first=True,init=True) + login(first=True, init=True) page.ele('tag:a@@text():青马课堂').hover() - page.ele('tag:a@@text():全部').click().for_new_tab() - click_videoes() - # 今日はこれで終わりです \ No newline at end of file + page.ele('tag:a@@text():全部').click() + click_videoes(study_type=study_type, class_info=class_info) + + +if __name__ == '__main__': + init() diff --git a/kill_course.py b/kill_course.py index 2444f02..8e27a9e 100644 --- a/kill_course.py +++ b/kill_course.py @@ -4,14 +4,16 @@ from collections import * import json from single_course import one_course from loguru import logger -def kill_course(again:bool=False): + + +def kill_course(again: bool = False): # 统计课程完成情况 cnt = defaultdict(list) # 读取课程信息 info = json.load(open('course_info.json', 'r')) for k, v in info.items(): if v['rate'] < 100: - cnt[v['type']].append((k,v['rate'])) # 课程类型作为键,课程id作为值 + cnt[v['type']].append((k, v['rate'])) # 课程类型作为键,课程id作为值 logger.info('{}'.format(cnt)) if not cnt: logger.info('所有课程均已完成') @@ -29,15 +31,16 @@ def kill_course(again:bool=False): if elective: course_info = elective.pop() logger.info('当前刷课序号:{}'.format(course_info[0])) - one_course(course_info[0], '选修', course_info[1],again=again) + one_course(course_info[0], '选修', course_info[1], again=again) if special: course_info = special.pop() logger.info('当前刷课序号:{}'.format(course_info[0])) - one_course(course_info[0], '专题', course_info[1],again=again) + one_course(course_info[0], '专题', course_info[1], again=again) if train: course_info = train.pop() logger.info('当前刷课序号:{}'.format(course_info[0])) - one_course(course_info[0], '培训', course_info[1],again=again) + one_course(course_info[0], '培训', course_info[1], again=again) + if __name__ == '__main__': - kill_course() \ No newline at end of file + kill_course() diff --git a/kill_quiz.py b/kill_quiz.py deleted file mode 100644 index d717169..0000000 --- a/kill_quiz.py +++ /dev/null @@ -1,5 +0,0 @@ -# 实现答题和评分 -''' -检测课程状态是否存在“未评价”或者“未答题”状态 -''' -from get_info import get_info diff --git a/main.py b/main.py index ecc7d99..3e881aa 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,5 @@ +from kill_course import kill_course +from initialization import init, click_videoes import json from get_info import get_info from collections import * @@ -7,13 +9,18 @@ from typing import * from DrissionPage import ChromiumPage from DrissionPage.common import * import time -# 获取课程信息 +from get_in import create_login_window +import os +# 录入账号密码 +if not os.path.exists('info.json'): + create_login_window() -# 这里以后会放一个初始化模块 +study_type = json.load(open('info.json', 'r'))['study_type'] -get_info(first=False) +# 这里以后会放一个初始化模块 +get_info(first=True) +init(study_type=study_type) # 执行刷课 -from kill_course import kill_course kill_course() # 完成刷课后,判定是否存在需要答题或者评分的课程 ''' @@ -22,15 +29,19 @@ kill_course() 2. 对于其他课存在3种情况:未完成,已完成,未评分 ''' # 重新获取课程信息 -def new_info() -> DefaultDict[str, List[Tuple[str,int,str]]]: + + +def new_info() -> DefaultDict[str, List[Tuple[str, int, str]]]: get_info(first=False) - new_info = json.load(open('course_info.json','r')) + new_info = json.load(open('course_info.json', 'r')) # 读取各个类别的课程状态 new_cnt = defaultdict(list) for k, v in new_info.items(): - new_cnt[v['type']].append((k,v['rate'],v['status'])) # 课程类型作为键,课程id作为值 + new_cnt[v['type']].append( + (k, v['rate'], v['status'])) # 课程类型作为键,课程id作为值 return new_cnt + new_cnt = new_info() # 首先检查是否还存在未完成的课程 for k, v in new_cnt.items(): @@ -49,15 +60,15 @@ not_quiz = [] for k, v in new_cnt.items(): for i in v: if i[2] == '未评分': - not_judged.append((i[0],k)) + not_judged.append((i[0], k)) elif i[2] == '未答题': - not_quiz.append(i[0],k) + not_quiz.append(i[0], k) # 实现自动评分 -def auto_judge(course_id:str,course_type:str) -> None: +def auto_judge(course_id: str, course_type: str) -> None: # 根据课程类型和id进行定位 - j_page = ChromiumPage() # 接管当前页面 + j_page = ChromiumPage() # 接管当前页面 # 判定课程类别 if course_type == '必修': j_page.ele('@value=1').click() @@ -78,17 +89,23 @@ def auto_judge(course_id:str,course_type:str) -> None: j_page.ele('tag:a@@text():保存').click() time.sleep(1) pass + + # 实现自动评分 if not_judged: for i in not_judged: logger.info('正在对课程:{}进行评分'.format(i[0])) - auto_judge(i[0],i[1]) + auto_judge(i[0], i[1]) logger.success('已完成对课程:{}的评分'.format(i[0])) else: logger.info('没有需要评分的课程') # 实现题目答案显示 -def auto_quiz(course_id:str) -> None: + + +def auto_quiz(course_id: str) -> None: pass + + if not_quiz: for i in not_quiz: logger.info('正在获取课程:{}的答案'.format(i[0])) @@ -106,13 +123,13 @@ not_quiz = [] for k, v in new_cnt.items(): for i in v: if i[2] == '未评分': - not_judged.append((i[0],k)) - elif i[2] == '未答题': - not_quiz.append(i[0],k) + not_judged.append((i[0], k)) + elif i[2] == '未完成作业': + not_quiz.append(i[0], k) if not not_judged and not not_quiz: logger.warning('所有课程均已完成,页面即将关闭') page = ChromiumPage() page.close_tabs() else: subprocess.run(["python", __file__]) - exit() \ No newline at end of file + exit() diff --git a/single_course.py b/single_course.py index e1db538..f733e2c 100644 --- a/single_course.py +++ b/single_course.py @@ -4,7 +4,8 @@ import time from loguru import logger # 实现单个课程的刷课逻辑 -def one_course(cid:str,ctype:str,crate:int,again:bool=False): + +def one_course(cid: str, ctype: str, crate: int, again: bool = False): ''' cid: 课程id ctype: 课程类型 @@ -38,17 +39,18 @@ def one_course(cid:str,ctype:str,crate:int,again:bool=False): if tr.ele('tag:td').text.split('\t')[0] == cid: # 进入视频页面 tr.ele('tag:button@@text():进入学习').click() - cur_page.wait.new_tab(timeout=3) # 等待新标签页出现 - tab = cur_page.get_tab(cur_page.latest_tab) # 获取新标签页 + cur_page.wait.new_tab(timeout=3) # 等待新标签页出现 + tab = cur_page.get_tab(cur_page.latest_tab) # 获取新标签页 time.sleep(1) if crate == 100: print('当前课程已完成') cur_page.close_tabs(tabs_or_ids=[tab]) # 进入后,获得当前视频的完成率,决定操作方式 - if tab.ele('tag:a@@text():继续学习',timeout=2): + if tab.ele('tag:a@@text():继续学习', timeout=2): tab.ele('tag:a@@text():继续学习').click() else: - tab.ele('c:#normalModel_video > xg-start > div.xgplayer-icon-play > svg > path').click() + tab.ele( + 'c:#normalModel_video > xg-start > div.xgplayer-icon-play > svg > path').click() # 建立循环,检测当前视频是否完播 '''
@@ -78,7 +80,7 @@ def one_course(cid:str,ctype:str,crate:int,again:bool=False): # 每60秒先检测是否有视频播放完毕 try: - if tab.ele('tag:div@@text():本小结已经学习完,是否进入下一节?',timeout=2): + if tab.ele('tag:div@@text():本小结已经学习完,是否进入下一节?', timeout=2): tab.ele('tag:a@@text():是').click() except: pass @@ -86,15 +88,19 @@ def one_course(cid:str,ctype:str,crate:int,again:bool=False): # 有时候没有弹窗提示,用以下方式手动检测 for i in l: if i != 100: - tab.ele('#normalModel_nodeList').eles('tag:div')[l.index(i)+1].click() + tab.ele('#normalModel_nodeList').eles( + 'tag:div')[l.index(i)+1].click() time.sleep(1) try: - if tab.ele('c:#normalModel_video > xg-start > div.xgplayer-icon-play > svg > path',timeout=2): - tab.ele('c:#normalModel_video > xg-start > div.xgplayer-icon-play > svg > path').click() + if tab.ele('c:#normalModel_video > xg-start > div.xgplayer-icon-play > svg > path', timeout=2): + tab.ele( + 'c:#normalModel_video > xg-start > div.xgplayer-icon-play > svg > path').click() except: pass - time.sleep(60) # 每次监测间隔60秒 + time.sleep(60) # 每次监测间隔60秒 + + break # なぜここにbreakがいるのですか?あかしいなあ。 + - break # なぜここにbreakがいるのですか?あかしいなあ。 if __name__ == '__main__': - one_course('6992','培训',68) \ No newline at end of file + one_course('6992', '培训', 68)