准备工具
- selenium
sudo pip3 install seletinum
- chromedriver
https://chromedriver.chromium.org/downloads - 放到
/usr/local/bin 目录下,代码可以不指定位置
基础知识
selenium 可以通过许多方法定位页面元素,这里简单列举下。
- 通过 id 定位
- 通过 name 定位
- 通过 tag_name 定位
- 通过 class_name 定位
- 通过 css 定位
- 通过 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 标签数量 |
- 通过 link 定位
异常处理
frame 处理
frame 是一个十分大的坑了,如果不注意当前页面的 frame,很有可能通过 selenium 定位不到元素。
frame 切换
延时处理
有可能我们的代码跑的太快了,但是当前 html 页面还没完全加载出来,导致定位不到元素。
- 利用 sleep 延时,绝对延时
- 隐性延时
最长是 30 秒,如果 30 秒内,资源全部加载完成,那么执行后续的代码,30 秒内没有加载完成,也会继续执行后续代码。
- 显性等待
等待时长 20 秒,间隔 0.5 秒去查询一次目标元素是否加载完成,20 秒内加载完成后,执行后续的代码,最长等待 20 秒,没有加载也会继续执行。
注意这里要查找的元素是元组。
alter 弹窗处理
接受
忽略
发送文本
获取文本内容
代码实现
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 发送给服务器,最后调用自动教学质量测评代码完成,没学过框架,代码写的很烂,就不贻笑大方了。