Three ways to achieve hanging video

Preface

Need to hang a video in a learning classroom. There is no interference during the video playback of this website, so just implement all the video clips under the course from beginning to end.

  • I have done the same video py script before, using python+selenium to achieve. So at first I wanted to use the same method to achieve this. This is the first method. Disadvantages: requires python and selenium webdriver. Compared with the other two methods, what are the advantages, I really can't think of it at present.
  • Since the playback action of the video and clicking the next segment are implemented by using selenium's webdriver.execute_script() function to send the js code to the browser for execution, it is to add some js code to the page. Suddenly remembered that such an implementation method using oil monkey script is not enough? You don't need python and webdriver, just open the video page on the browser where you installed the oil monkey to add the auto play function. This is the second method. Disadvantages: You need a browser (firefox/chreom/edge) that can install the oil monkey, install the oil monkey extension, and add scripts to the oil monkey, which is really not friendly enough for the computer Xiaobai. Advantages: The function is implemented directly in the browser, and it will work automatically when the video page is opened, no other operations are required.
  • Inspired by the third way of using Reabble's Sent to Kindle, make the js code a bookmark button, and then enter the video page and click the bookmark button. Disadvantages: You have to know how to set the bookmark button and set the "Show Favorites Bar" in your browser. Advantages: As long as the js code is made into a bookmark in advance (the same thing as the web shortcut in the IE favorites, different name), and then you take it to any browser, just click the bookmark in the favorites bar to enable it The automatic playback function is convenient and simple to use.

Of the three methods, I prefer to use the third. Because as long as you write down the js code, it can be used no matter where you are and what browser you are using, and you don't need to install other software or extensions.

The first method: phthon+selenium

The V0.1 version realized the basic functions, and then the V0.2 version did an object-oriented refactoring. Because I thought of a more convenient way to implement it, I didn't continue to optimize the code carefully.

# 通服云课堂 自动播放视频
# V0.2  :功能重构
import time

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

LOGIN_URL = 'https://www.ccspx.com.cn/login'
USER = '*******'
PWD = '*******'

driver = webdriver.Edge(executable_path='msedgedriver.exe')


class Player:
    def __init__(self, parallel_num, proceed, task_center_title='任务中心'):
        self.parallel_num = parallel_num
        self.proceed = proceed
        self.task_center_title = task_center_title
        self.tasks = []

        self.logined = False

    def run(self):
        self._login()
        self._create_tasks()
        for task in self.tasks:
            task.start()
            time.sleep(3)

        for task in self.tasks:
            print(f'{task.name}\n{task.command}\n{task.video_fragment_commands}\n----------------------')

        while self.tasks:
            time.sleep(10)
            for i in range(len(self.tasks)):
                self.tasks[i].check_video_ended()
                if self.tasks[i].completed:
                    self.tasks.remove(self.tasks[i])

    def _login(self):
        driver.get(LOGIN_URL)
        time.sleep(1)
        driver.find_element_by_id('username').send_keys(USER)
        driver.find_element_by_id('password').send_keys(PWD)
        driver.find_element_by_id('validateCode').click()

        while True:
            try:
                driver.find_element_by_id('username')
            except NoSuchElementException:
                self.logined = True
                break
            time.sleep(2)

    def _create_tasks(self):
        window = None
        while window is None:
            time.sleep(10)
            for w in driver.window_handles:
                driver.switch_to.window(w)
                if driver.title == self.task_center_title:
                    window = w

        driver.switch_to.window(window)
        time.sleep(2)
        task_commands = [a.get_attribute('onclick') for a in
                         driver.find_elements_by_xpath('//div[@id="dataList"]//li/a')]
        progresses = [span.text for span in driver.find_elements_by_xpath('//div[@id="dataList"]//li//span')]
        for c, p in zip(task_commands, progresses):
            if self.proceed:
                if p != '100%':
                    self.tasks.append(Task(command=c, parent_window=window, proceed=self.proceed))
            else:
                self.tasks.append(Task(command=c, parent_window=window, proceed=self.proceed))


class Task:
    def __init__(self, command, parent_window, proceed):
        self.command = command
        self.parent_window = parent_window
        self.proceed = proceed

        self.running = False
        self.completed = False
        self.name, self.window = None, None

        self.video_fragment_commands = []

    def start(self):
        driver.switch_to.window(self.parent_window)
        driver.execute_script(self.command)
        time.sleep(3)
        self.window = driver.window_handles[-1]
        driver.switch_to.window(self.window)
        self.name = driver.title

        self._get_video_fragments()
        self._play()

    def _get_video_fragments(self):
        driver.switch_to.window(self.window)
        fragment_commands = [li.get_attribute('onclick') for li in
                             driver.find_elements_by_xpath('//li[contains(@class, "task-item")]')]
        progresses = [sp.text for sp in driver.find_elements_by_xpath('//li[contains(@class, "task-item")]//span')][
                     2::3]
        for c, p in zip(fragment_commands, progresses):
            if self.proceed:
                if p != '100%':
                    self.video_fragment_commands.append(c)
            else:
                self.video_fragment_commands.append(c)

    def _play(self):
        if len(self.video_fragment_commands) != 0:
            driver.switch_to.window(self.window)
            driver.execute_script(self.video_fragment_commands[0])
            time.sleep(2)
            driver.execute_script('document.getElementsByTagName("video")[0].play();')
        else:
            self.completed = True
            driver.execute_script('alert("页面无视频或采集错误");')

    def check_video_ended(self):
        driver.switch_to.window(self.window)
        if driver.find_element_by_tag_name('video').get_property('ended'):
            self.video_fragment_commands.pop(0)
            if len(self.video_fragment_commands) == 0:
                self.completed = True
                driver.execute_script('alert("视频播放完毕");')
                # driver.close()
            else:
                self._play()
        else:
            driver.execute_script('document.getElementsByTagName("video")[0].play();')

    def __repr__(self):
        return f'{self.__class__.__name__}(name={self.name}, command={self.command}, ' \
               f'video_fragments={self.video_fragment_commands})'


def main():
    player = Player(parallel_num=5, proceed=False)
    player.run()


if __name__ == '__main__':
    main()

The second method: use oil monkey extension

Idea: Add a timer caller setInterval. Execute once every 4 seconds to check whether the video playback is over (judge player.ended), and play the next segment.

// ==UserScript==
// @name         通服云课堂 - 自动播放/静音
// @namespace    *
// @version      0.1
// @description  自动播放“通服云课堂”视频
// @author       czbuyi
// @match        https://www.ccspx.com.cn/course/detail*
// @grant        none
// ==/UserScript==

(function() {
    
    
    if(confirm("开始视频自动播放?")){
    
    
        setInterval(function(){
    
    
            let player = document.getElementsByTagName('video')[0];
            if(player.ended){
    
    
                let all = [].slice.call(document.getElementsByClassName('task-item'));
                let active = document.getElementsByClassName('task-item active')[0];
                let next_index = all.indexOf(active)+1;
                console.log(all.indexOf(active));
                if (next_index <= all.length-1){
    
    
                    all[next_index].click();
                }else{
    
    
                    alert("视频播放结束");
                    window.close();
                }
            };
            player.play();
            player.muted=true;
        }, 4000)
    }
    // Your code here...
})();

The third method: use the label button

The js code is the same as the second method. In order to make a label, add "javascript:" in front of the js code and remove the carriage return and arrange it into one line.

javascript:(function(){
    
    if(confirm("开始视频自动播放?")){
    
    setInterval(function(){
    
    let player=document.getElementsByTagName('video')[0];if(player.ended){
    
    let all=[].slice.call(document.getElementsByClassName('task-item'));let active=document.getElementsByClassName('task-item active')[0];let next_index=all.indexOf(active)+1;if(next_index<=all.length-1){
    
    all[next_index].click();}else{
    
    alert("视频播放结束");window.close();}};player.play();player.muted=true;},4000)}})();

Record a few pits

  • To find and operate an element or test js code in a web page, I have always used running code (through python, or html, js script) to detect it. Every time it may involve logging in, clicking to the target page, refreshing, etc., it is wasteful I spent a lot of time and energy. Later, I discovered that you can directly enter the test in the console of the browser "debugging tool" (press F12 to call it out), and you can see the result immediately, which is very direct and convenient.
  • The video element on the video playback page of this website will change, so you need to get the video element again for each operation. Due to the same problem, the end event cannot be added to the video element to handle the operation after the video clip is played.
  • In order to achieve continuous playback, the il element of the next segment needs to be found. However, there are some differences in the structure of each page, so I had to find all the il with the "task-item" type in the page and convert it into an array, and then search for the il element of the "task-item active" type, and check its position in the array. Determine the il of the next fragment.
  • The document.getElementsBy*** of js returns an HTMLCollection object, which is similar to an array and can be traversed with for, but without the function of indexOf, it is impossible to determine the position of an element in the object. Because I need to find the il of the current "task-item active" class and click the next il element to play the next snippet, I can only convert the HTMLCollection object into an array: all = [].slice.call(document. getElementsByClassName('task-item'))
  • The attributes defined in the <> of the html element can be obtained using getAttribute("attribute name"), such as video element.getAttribute("scr"). However, the state of the video element, such as "ended" at the end of playback, "muted" in the mute state, etc., is directly judged by using the video element .ended.

Guess you like

Origin blog.csdn.net/qq_41090453/article/details/114163656