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
main
JesterHey 12 months ago
parent d680b1f2a1
commit b1285b5d8e

File diff suppressed because one or more lines are too long

@ -1,20 +1,10 @@
from DrissionPage import ChromiumPage
from DrissionPage.common import *
from loguru import logger
import subprocess
from get_info import login
# page = ChromiumPage()
# page.get('http://hnqmgc.17el.cn/')
# try:
# if page.ele('@onclick=cha()',timeout=3):
# page.ele('@onclick=cha()').click()
# # <img style="width: 25px;height: 25px;" src="/images/index/cha.png" alt="" srcset="">
# 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)
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))

@ -1 +0,0 @@
2024-03-10T12:13:35.955107+0800 DEBUG 这是一条具有自定义格式的日志信息

@ -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()

@ -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()
# <img style="width: 25px;height: 25px;" src="/images/index/cha.png" alt="" srcset="">
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 = {}
# <div class="paginationjs-nav J-paginationjs-nav">1 / 4</div>
# 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()
create_login_window()
get_info()

@ -0,0 +1 @@
{"username": "51140220050507901X", "password": "hnqm123456", "study_type": "\u7f51\u7edc\u6587\u660e\u5fd7\u613f\u8005"}

@ -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()
# 今日はこれで終わりです
page.ele('tag:a@@text():全部').click()
click_videoes(study_type=study_type, class_info=class_info)
if __name__ == '__main__':
init()

@ -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()
kill_course()

@ -1,5 +0,0 @@
# 实现答题和评分
'''
检测课程状态是否存在未评价或者未答题状态
'''
from get_info import get_info

@ -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()
exit()

@ -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()
# 建立循环,检测当前视频是否完播
'''
<div id="normalModel_nodeList" style="max-height:550px;overflow:auto;">
@ -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)
one_course('6992', '培训', 68)

Loading…
Cancel
Save