项目地址

Elevenlong1101/script-for-yuketang: selenium 简单实现雨课堂刷课,无需配置浏览器驱动,一键启用 (github.com)

登陆过程实现

由于作者太懒了,直接time.sleep()手动扫码

准备工作

1
2
3
4
5
6
7
8
9
10
11
12
13
print("本脚本仅支持雨课堂平台\n")

print("牛魔雨课堂不得好死!!!\n")

name = input("请输入您想刷的课程名称:\n")

time.sleep(2)

print("接下来请在弹出的浏览器页面中扫码登陆,登陆后等待一段时间程序会自动开始运行\n")

print("想要退出刷课,只要退出浏览器窗口即可\n")

time.sleep(2)

各种输入输出,方便他人进行使用

隐藏selenium特征

1
2
3
4
5
6
7
8
9
10
11
12
option = webdriver.EdgeOptions()
# 创建浏览器设置实例
option.add_experimental_option('excludeSwitches', ['enable-automation'])
# 禁止显示浏览器上方“chrome正受自动测试软件控制”字样
prefs = {'credentials_enable_service': False, 'profile.password_manager_enabled': False}
option.add_experimental_option('prefs', prefs)
option.add_argument('--disable-blink-features=AutomationControlled')
# 隐藏windows.navigator.driver参数,通常为undefined 使用selenium则为true
option.add_argument('--mute-audio')
# 可选 静音启动浏览器
option.binary_location = 'selenium\edge117\msedge.exe'
# 可选 配置浏览器启动位置

创建浏览器实例

1
2
3
4
5
6
7
s = Service("selenium\msedgedriver117.exe")
driver = webdriver.Edge(service= s,options= option)
# 创建浏览器实例以及配置一下浏览器驱动位置
driver.get("https://xxxxx.yuketang.cn/web")

# 接下来开始登陆
time.sleep(10)# 给时间扫码

要注意的是,以上配置浏览器启动位置和浏览器驱动位置都应该注意一下相对路径,最好直接在vscode里面直接右键,复制相对路径,不要像我一样看了一下午如何配置浏览器驱动发现其实是相对位置写错了。。。md我花了五个小时

找到需要刷的课程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tab_student = driver.find_element(By.ID, 'tab-student')
# 找到所有课程按钮的元素
tab_student.click()
# 点击跳转到所有课程
time.sleep(1)
# 等待加载
class_btn = driver.find_element(By.XPATH, f'//*[@id="pane-student"]//h1[contains(text(),{name})]')
# 根据开头输入的名字找到要刷的课程
class_btn.click()
# 点击进入
grade = driver.find_element(By.XPATH, '//div[@id="tab-student_school_report"]/span')
grade.click()
time.sleep(1)
# 进入课程成绩单页面

这里注意,基本上所有涉及到刷新,加载等操作的地方都要sleep一下,或者直接隐式等待,主要取决于使用者的网速如何,否则会花费大量时间去排错。。。又是一个小时md

由于在课程主页面直接开刷会出问题(纯纯就是垃圾某课堂网页版没写好出的bug,吐槽一下,上课数量多了之后课程完成状态居然不显示。。。),所以多写两行跳转到成绩单页面再开始刷

开始刷课

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def study():

    lessons = driver.find_elements(By.XPATH, '//li[@class="study-unit"]')
# 找到课程列表
    for lesson in lessons:

        statistic = lesson.find_element(By.CSS_SELECTOR, 'div.complete-td span').text
# 读取课程完成状态
        if statistic == "已完成" or statistic == "已发言" or statistic == "未发言" or  statistic == "未开始":

            continue # 判断课程状态

        else:

            lesson_btn = lesson.find_element(By.CSS_SELECTOR, '.name-text')

            driver.execute_script("$(arguments[0]).click()", lesson_btn)# 点击进入课程按钮
            time.sleep(2)

            driver.switch_to.window(driver.window_handles[-1])# 切换到课程窗口

            #volume_btn = driver.find_element(By.XPATH, '//xt-icon')

            #driver.execute_script("$(arguments[0]).click()", volume_btn)# 静音播放

            finish_bar = driver.find_element(By.XPATH, '//span[@class="text"]').text

            while finish_bar != "完成度:100%":

                time.sleep(5)

                finish_bar = driver.find_element(By.XPATH, '//span[@class="text"]').text# 每五秒刷新状态值

            driver.close()

            driver.switch_to.window(driver.window_handles[0])# 关闭刷课窗口并回到成绩单窗口
            driver.refresh()# 刷新窗口获得课程完成状态

            time.sleep(1)

            grade = driver.find_element(By.XPATH, '//div[@id="tab-student_school_report"]/span')

            grade.click()

            time.sleep(1)# 点击转换到成绩单窗口



            study()
           
study()

总结

刷课部分倒没什么含金量,主要是各种细节很让人难受,例如文件的相对路径,浏览器的配置等等,很让人难受,整体写下来虽然磕磕绊绊,但也算有了结果,第一次写出来的东西,也不算完美吧,其实主要时间都花在解决乐色某课堂网页版的bug上了。。。

学到了很多

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# 雨课堂刷课脚本2.0 不同思路进行重构

# 学习:静音开启浏览器

# 学习:切换窗口

# 学习:根据文本定位

# 学习:文本输入

# 学习:要取相对路径不要自己写,直接复制就好了!!!驱动和浏览器路径写错selenium不会报错,只会找默认路径的驱动和浏览器!

# 学习:导包的时候要注意路径问题,写的是edge还是chrome

# 学习:在哪里运行这个文件也很重要,这关系到文件中需要读取的文件的相对路径能否被找到



from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.edge.service import Service

import time



# 事先声明



print("本脚本仅支持雨课堂平台\n")

print("牛魔雨课堂不得好死!!!\n")

name = input("请输入您想刷的课程名称:\n")

time.sleep(2)

print("接下来请在弹出的浏览器页面中扫码登陆,登陆后等待一段时间程序会自动开始运行\n")

print("想要退出刷课,只要退出浏览器窗口即可\n")

time.sleep(2)



# 隐藏特征



option = webdriver.EdgeOptions()

option.add_experimental_option('excludeSwitches', ['enable-automation'])

prefs = {'credentials_enable_service': False, 'profile.password_manager_enabled': False}

option.add_experimental_option('prefs', prefs)

option.add_argument('--disable-blink-features=AutomationControlled')

option.add_argument('--mute-audio')

option.binary_location = 'selenium\edge117\msedge.exe'



# 浏览器实例



s = Service("selenium\msedgedriver117.exe")

driver = webdriver.Edge(service= s,options= option)

driver.get("https://xxxxx.yuketang.cn/web")



# 开始登陆



time.sleep(10)# 给时间扫码



# 找到课程



tab_student = driver.find_element(By.ID, 'tab-student')

tab_student.click()

time.sleep(1)

class_btn = driver.find_element(By.XPATH, f'//*[@id="pane-student"]//h1[contains(text(),{name})]')

class_btn.click()



time.sleep(1)

# 点击成绩单页面



grade = driver.find_element(By.XPATH, '//div[@id="tab-student_school_report"]/span')

grade.click()

time.sleep(1)

# 刷课



def study():

    lessons = driver.find_elements(By.XPATH, '//li[@class="study-unit"]')

    for lesson in lessons:

        statistic = lesson.find_element(By.CSS_SELECTOR, 'div.complete-td span').text

        if statistic == "已完成" or statistic == "已发言" or statistic == "未发言" or  statistic == "未开始":

            continue # 判断课程状态

        else:

            lesson_btn = lesson.find_element(By.CSS_SELECTOR, '.name-text')

            driver.execute_script("$(arguments[0]).click()", lesson_btn)# 点击进入课程按钮

            time.sleep(2)



            driver.switch_to.window(driver.window_handles[-1])# 切换到课程窗口



            #volume_btn = driver.find_element(By.XPATH, '//xt-icon')

            #driver.execute_script("$(arguments[0]).click()", volume_btn)# 静音播放



            finish_bar = driver.find_element(By.XPATH, '//span[@class="text"]').text

            while finish_bar != "完成度:100%":

                time.sleep(5)

                finish_bar = driver.find_element(By.XPATH, '//span[@class="text"]').text# 每五秒刷新状态值

            driver.close()

            driver.switch_to.window(driver.window_handles[0])# 关闭刷课窗口并回到成绩单窗口



            driver.refresh()# 刷新窗口获得课程完成状态

            time.sleep(1)

            grade = driver.find_element(By.XPATH, '//div[@id="tab-student_school_report"]/span')

            grade.click()

            time.sleep(1)# 点击转换到成绩单窗口



            study()



study()



time.sleep(5)