前言

学校在智慧树平台安排有课程,我不想学但不得不学,就这么简单。(这种大逆不道的话你也敢说的吗兄嘚)。

啊哈哈哈,那当然不是了。我是热爱学习,渴望用知识的力量武装自己的当代油锈大学生,学校为我们提供了如此精良的课程,我们当然不能辜负学校的良苦用心才是啊。

可是!可是!某人听课有个习惯,一定是全神贯注仔细听讲。因为哪怕只有一点点外界干扰,都会影响整体的心流状态,如果因为这个原因,影响了学习掌握新知识的效率,那真的会痛心不已(脸皮是真的厚)。

请诸位试想,你正津津有味地聆听网课老师的绝妙理论,沉浸其中无法自拔时,突然,跳出来一个弹窗暂停了视频播放,中断了你的听课状态,要求你答题,答完题才能接着看,你说说,这不是欺负老实人吗。我就想安安静静听课,课后练习题,你等我听完课再让去做不好么。真的是,猴猴急。

还有还有,你看完一节网课,掌握了更多新知识的同时,心中多多少少也有更多的疑惑,迫切想听接下来的课程,从中获取到你想要的答案。可惜智慧树它偏不,它在播放完一节网课之后竟然不能自动播放下一个视频。连这样简单的自动连播都不给实现,这我不能忍了。既然如此,那就由我来“调教”一下。

那需求就是:首先,应该“跳过”视频播放过程中出现的问题小弹窗,然后,实现视频自动连播功能。

直接安排!

实现

#导入需要的库
from selenium import webdriver                                      #selenium库,核心库,webdriver对象用来操作浏览器
from selenium.webdriver.common.by import By                         #用于定位页面元素
from selenium.webdriver.common.action_chains import ActionChains    #处理鼠标事件(如鼠标悬停等)
from time import sleep                                              #time标准库,用于程序休眠

设定一些启动参数,比如关闭Selenium的控制台日志,让控制台清爽一点。

options = webdriver.EdgeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])  #关闭selenium日志输出
options.add_argument("--mute-audio")                                    #浏览器静音
Edge = webdriver.Edge(options=options)                                  #创建webdriver对象
    Edge.implicitly_wait(10)                                            #设定全局等待时间,10秒

 

接下来,用代码打开智慧树官网主页,检查【登录】的元素,很棒啊!智慧树很给面子地用一个id标识了登录按钮。那我们要实现模拟点击【登录】,只需要用这个id在Selenium中定位就好了。

写个死循环,让程序一直检测视频播放页面的元素。如果检测到并能成功点击,说明用户已经顺利进入了视频播放界面。为什么要用死循环呢?因为当我们模拟点击登录之后,智慧树跳转进入用户登录页面等待用户登录。而用户什么时候登录完成,并进入视频播放界面,我们是不能确定的。但是后续代码必须保证当前页面在视频播放页面才能继续执行,所以写一个死循环,当条件满足时用break退出去,正常执行后续代码。什么?你问我如果用户迟迟不等登录,或者用户操作不当,没有进入视频播放界面怎么办?怎么办,简单啊,让它一直死循环就好了,直到用户进入了正确的页面,这样可以规避了因用户操作问题导致的程序崩溃。

直到用户进入视频播放页面,我们在视频播放页面找个元素,这个元素要保证,一旦循环找到了这个元素,就确实能证明我进入了这个页面,可以退出循环执行后续代码。我找的元素是这个。

智慧树还是很温柔地,用一个class标识了这个元素,我们还是可以很轻易地定位到它。代码如下。

Edge.get("http://www.zhihuishu.com/")                                   #打开知到智慧树官网
Edge.find_element(By.ID,"notLogin").click()                             #定位到【登录】
    while True:                                                         #等待用户登录、进入课程
        try:
            Edge.find_element(By.CLASS_NAME,"hint_delete").click()
        except:
            print("未找到课程")
        else:
            break

okk,到了这里,万事俱备,可以着手实现功能了。首先。要实现自动播放下一个视频,需要知道当前课程总共有多少视频、现在已经看完的视频有几个。

通过查找页面元素我们发现,智慧树将每一个视频统一用一个class标识,所以我们只需要用.find_elements()方法,这个方法返回一个列表,能获取到所有指定特征的元素,那么这个列表的长度,就是课程数量。同理,智慧树将以看完的课程后面标识了一个小图标,我们只需要获取到这个小图标的个数,就能得到已经看完的课程数量。

 代码如下:

icofinishlist = Edge.find_elements(By.CLASS_NAME,"fl.time_icofinish")   #存放已完成的课程,列表
Allvideolist = Edge.find_elements(By.CLASS_NAME,"clearfix.video")    #存放全部课程,列表
Allvideolist[len(icofinishlist)].click()                             #进入未完成的第一个课程

说到这里,我想应该能够体会selenium定位元素的方法了吧。后面的代码部分原理还是一样的,找元素,点击元素就好了,元素的特征定位也很简单,基本上全是通过class就能定位。直接贴代码:

sleep(5)
videoArea = Edge.find_element(By.CLASS_NAME,"videoArea")                #视频播放区域
ActionChains(Edge).move_to_element(videoArea).perform()                 #鼠标悬停
speedBox = Edge.find_element(By.CLASS_NAME,"speedBox")                  #视频倍速按钮
ActionChains(Edge).move_to_element(speedBox).perform()                  #鼠标悬停
Edge.find_element(By.CLASS_NAME,"speedTab.speedTab15").click()          #视频1.5倍速
definiBox = Edge.find_element(By.CLASS_NAME,"definiBox")                #视频清晰度按钮
ActionChains(Edge).move_to_element(definiBox).perform()                 #鼠标悬停
Edge.find_element(By.CLASS_NAME,"line1bq.switchLine").click()           #视频【流畅】清晰度
Edge.find_element(By.ID,"playButton").click()                           #视频播放按钮
while True:                                                             #循环,检测小弹窗
    try:
        Edge.find_elements(By.CLASS_NAME,"topic-item")[0].click()       #小弹窗选项,默认选第一个(A)
    except:
        print("未检测到小测验弹窗")
    else:
        print("检测到小测验弹窗")
        btn1 = Edge.find_element(By.CLASS_NAME,"el-dialog__wrapper.dialog-test")
        btn2 = btn1.find_element(By.CLASS_NAME,"el-dialog")
        btn3 = btn2.find_element(By.CLASS_NAME,"el-dialog__headerbtn").click()
        sleep(3)
        videoArea = Edge.find_element(By.CLASS_NAME,"videoArea")        #视频播放区域
        ActionChains(Edge).move_to_element(videoArea).perform()         #鼠标悬停
        Edge.find_element(By.ID,"playButton").click()                   #重新播放视频
        break

关于代码中鼠标悬停那部分,是因为智慧树的视频播放界面,播放、调整倍速、调整清晰度等等这些控件,是要用户先将鼠标悬停到视频播放区域才会可见的。于是我们用Selenium提供的ActionChains类模拟鼠标操作,实现悬停。然后是死循环,不停检查视频内小弹窗元素。当弹窗出现时,随便点击一个问题的答案,关闭小弹窗就可以了。这样第一个功能:“跳过”视频内小弹窗,就这样实现了。

接下来用一个大循环,不断检查现在已经看完的视频列表(也就是能代表视频已经看完的那个小图标)有没有新增。如果有新增,说明当前视频已经播放完毕了,可以进入下一个视频了。这样就实现了自动连播,代码如下:

while True:
    Nowicofinish = Edge.find_elements(By.CLASS_NAME,"fl.time_icofinish")
    if len(Nowicofinish) == len(icofinishlist)+1:
        icofinishlist = Edge.find_elements(By.CLASS_NAME,"fl.time_icofinish")       #更新已完成的课程,列表
        Allvideolist[len(icofinishlist)].click()                                    #进入下一个未完成的课程
        print("进入下一课")
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐