利用selenium自动完成教学质量测评

准备工具

  • selenium
    • sudo pip3 install seletinum
  • chromedriver
    • https://chromedriver.chromium.org/downloads
    • 放到/usr/local/bin目录下,代码可以不指定位置

基础知识

selenium 可以通过许多方法定位页面元素,这里简单列举下。

driver = webdrriver.Chrome()

  1. 通过 id 定位

driver.find_element_by_id()

  1. 通过 name 定位

driver.find_element_by_name()

  1. 通过 tag_name 定位

driver.find_element_by_tag_name()

  1. 通过 class_name 定位

driver.find_element_by_class_name()

  1. 通过 css 定位

driver.find_element_by_css_selector

  1. 通过 xpath 定位

driver.find_element_by_xpath

xpath 简单语法

表达式 概述
//div 选取所有的 div 元素
//div[@class=“blog-content-box”] 选取 class 为 cblog-content-box 的元素
//div/link/@href 选取所有 div 标签下的 link 标签的链接
//div/h2/text() 选取 所有 div 标签下的 h2 标签之间的内容
//div[1]/p 选取第一个 div 标签下的 p 标签的内容
//div[1]/p[last()] 选取第一个 div 标签下的 p 标签的最后一个内容
//div[@class^=“blog”] 选取所有以 blog 开头的 div 标签
etree.HTML(html).xpath(‘count(//div/form)’) 计算所有的 div 标签下的 form 标签数量
  1. 通过 link 定位

driver.find_element_by_link_text()取链接中的所有元素

driver.find_element_by_partial_link_text()取链接中的部分元素

异常处理

frame 处理

frame 是一个十分大的坑了,如果不注意当前页面的 frame,很有可能通过 selenium 定位不到元素。

frame 切换driver.switch_to_frame(driver.find_element_by_tag_name("iframe"))

延时处理

有可能我们的代码跑的太快了,但是当前 html 页面还没完全加载出来,导致定位不到元素。

  1. 利用 sleep 延时,绝对延时

time.sleep(秒数)

  1. 隐性延时

最长是 30 秒,如果 30 秒内,资源全部加载完成,那么执行后续的代码,30 秒内没有加载完成,也会继续执行后续代码。

driver.implicitly_wait(秒数)

  1. 显性等待

等待时长 20 秒,间隔 0.5 秒去查询一次目标元素是否加载完成,20 秒内加载完成后,执行后续的代码,最长等待 20 秒,没有加载也会继续执行。

WebDriverWait(driver,20,0.5).until(EC.presence_of_element_located(要草找的元素))

注意这里要查找的元素是元组。

alter 弹窗处理

接受driver.switch_to.alert.accept()

忽略driver.switch_to.alert.dismiss()

发送文本driver.switch_to.alert.send_keys(文本内容)

获取文本内容driver.switch_to.alert.text

代码实现

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
#! /usr/bin/python3.8
import requests
import sys
from selenium import webdriver
import time
from lxml import etree


class Table:
    def __init__(self, number_id, passwd):
        self.url = "学校官网地址"
        self.number_id = number_id
        self.passwd = passwd

    def simulate(self):
        # 启动
        driver = webdriver.Chrome()
        # 最大化
        driver.maximize_window()
        # 地址请求
        driver.get(self.url)
        # 登录
        driver.find_element_by_id("username").send_keys(self.number_id)
        driver.find_element_by_id("password").send_keys(self.passwd)
        driver.find_element_by_class_name("btn_dl").click()
        time.sleep(1)
        # 进入教务系统
        driver.find_element_by_id("157889684646655577").click()
        # 切换到最新的页面
        windows = driver.window_handles
        driver.switch_to.window(windows[-1])
        time.sleep(1)
        # 切换到测评页面
        driver.find_element_by_xpath(
            "/html/body/div[1]/div[1]/div[2]/ul/li[4]/a/span").click()
        driver.find_element_by_xpath(
            "/html/body/div[1]/div[1]/div[2]/ul/li[4]/ul/li[1]/a").click()
        time.sleep(1)
        # 有frame,需要转换
        driver.switch_to_frame(driver.find_element_by_tag_name("iframe"))
        time.sleep(1)
        # 计算有多少门课要测评
        html = etree.HTML(driver.page_source)
        size = html.xpath(
            'count(/html/body/form/div[3]/div/div[2]/div/div[1]/select/option)')
        size = int(size)
        # 利用js完成选项
        commond = "document.getElementById('{}').options[{}].selected = true;"
        for j in range(size):
            # 找到每一门课程有多少个评价
            time.sleep(1)
            html = etree.HTML(driver.page_source)
            id_lists = html.xpath("//td/select/@id")
            for i in id_lists:
                # 防止评价重复
                if i == "DataGrid1_JS1_14" or i == "DataGrid1_JS2_14":
                    end = commond.format(i, 2)
                else:
                    end = commond.format(i, 1)
                driver.implicitly_wait(7)
                # time.sleep(1)
                driver.execute_script(end)
            try:
                time.sleep(2)
                driver.find_element_by_name("Button1").click()
            except Exception as e:
                driver.refresh()
                time.sleep(2)
                driver.find_element_by_name("Button1").click()
            else:
                print("success")
        time.sleep(1)
        driver.switch_to.alert.accept()
        time.sleep(1)
        driver.find_element_by_name("Button2").click()
        time.sleep(5)
        driver.quit()
        print("---end----")

    def run(self):
        print("---start----")
        self.simulate()


if __name__ == "__main__":
    if len(sys.argv) == 3:
        number_id = sys.argv[1]
        passwd = sys.argv[2]
    else:
        print("./文件名 学籍号 密码")
        sys.exit()
    table = Table(number_id, passwd)
    table.run()

注:每个学校的官网不同,需要自己定位到元素操作。

总结

还是直接用 js 舒服,哈哈哈,js 太强了。

js 代码:copy 龙哥

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
setInterval(function(){
    var select = document.getElementById("iframeautoheight").contentWindow.document.getElementsByTagName('select');
    for (var j = 1; j < select.length; j++) {
        if (j != select.length - 1) {
            select[j].options[1].selected = true;
        } else {
            select[j].options[2].selected = true;
        }
    }
    if(select.length>16){
        select[10].options[2].selected = true;
    }
    setTimeout(function() {
        var elements = document.getElementById("iframeautoheight").contentWindow.document.getElementsByTagName('input');
        for (var i = 0; i < elements.length; i++) {
            if(elements[i].value == "保  存"){
                elements[i].click();
            }
        }
    }, 1000)
},5000);

setTimeout(function(){
    var element = document.getElementById("iframeautoheight").contentWindow.document.getElementsByTagName('input');
    for (var i = 0; i < element.length; i++) {
        if(element[i].value == " 提  交 "){
            element[i].click();
        }
    }
},62000)

最后还搞了个 html 输入学籍号和密码,通过 post 发送给服务器,最后调用自动教学质量测评代码完成,没学过框架,代码写的很烂,就不贻笑大方了。