详细又简单的小白抢课教学——通过selenium配合chromedriver模拟手动操作进行抢课,以北航教务系统为例。
实现效果
大概一秒2-3次,多开的话,没有上限,一秒百次都是可能的。
环境配置
python3.8
selenium包
pip install selenium
即可chromedriver.exe
- 首先查看本地Chrome版本,在Chrome输入栏中输入
chrome://version/
后第一行为版本号。
之后下载相应版本的chromedriver
镜像网站:https://npm.taobao.org/mirrors/chromedriver/
官方网站:https://sites.google.com/a/chromium.org/chromedriver/home
下载完后,chromedriver.exe和py文件放在同一目录下
- 首先查看本地Chrome版本,在Chrome输入栏中输入
代码流程
import
# 引入selenium
# 引入chromedriver
# 引入Select用于选择
# 引入time对频率进行控制
import selenium
from selenium.webdriver import Chrome
from selenium.webdriver.support.ui import Select
import time
打开网页
# 打开Chrome
chrome = Chrome()
# 打开教务系统
chrome.get("http://jwxt.buaa.edu.cn:7001/ieas2.1/welcome?falg=1")
如下图所示,此时我们可以用chrome对象实现对它的完全操控。
登录
之后需要输入学号和密码,那么就需要使得程序锁定到用户名和密码输入框,最通用的方法是利用find_element_by_xpath函数,通过元素的xpath来定位元素。
那么如何知道元素的xpath呢?在打开的网页上使用快捷键 Shift + Ctrl + C
,这时候将鼠标放在用户名输入框中,整个输入框都会变蓝,代表鼠标正聚焦在这个元素。(右侧突然出现的是Chrome的元素分析栏)。
此时点击一下输入框,右侧分析栏自动定位此元素,然后对其右键->copy->copy_full_XPath,这时候就得到了此元素的xpath。
# 定位用户名并输入用户名,用send_keys函数来输入
chrome.find_element_by_xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/div[1]/div/input").send_keys("12345678")
# 密码
chrome.find_element_by_xpath('/html/body/div[2]/div/div[3]/div[2]/div[1]/div[3]/div/input').send_keys("******")
一般这样就可以达到效果了,但实际操作上,当我们运行上述两行代码时会报错:NoSuchElementException。
当时我也寻找了很长时间原因,后来发现是由于网页用到了iframe,也就是网页中的网页,也就是我们要定位的输入框实际上是位于iframe中的。
那么我们就需要将chrome聚焦于这个iframe,然后再用xpath来定位。
# 通过xpath定位iframe元素
iframe = chrome.find_element_by_xpath("/html/body/iframe")
# 使得chrome对象聚焦于iframe
chrome.switch_to.frame(iframe)
# 定位用户名并输入用户名,用send_keys函数来输入
chrome.find_element_by_xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/div[1]/div/input").send_keys("12345678")
# 密码
chrome.find_element_by_xpath('/html/body/div[2]/div/div[3]/div[2]/div[1]/div[3]/div/input').send_keys("******")
执行效果如下。
接下来只需要点击登录按钮即可,同理使用快捷键 Shift + Ctrl + C
,鼠标点击登录按钮,在右侧copy_full_XPath得到xpath。定位完成后,使用click函数完成点击操作。
# 点击登录
chrome.find_element_by_xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/div[7]/input").click()
如果输入的用户名和密码都对的话,就会进入到如下的选课网页。至此,登录完成,其实到现在,实现选课的基本操作已经讲完了,无非都是用xpath来找到元素,实现点击(click)或者输入(send_keys)操作。
选课
同样方法点击学生选课,专业课程。
# 点击学生选课
chrome.find_element_by_xpath("/html/body/div[2]/div[1]/div[1]/div[2]/div/a[6]/div").click()
# sleep是为了等待网页动画
time.sleep(1)
# 点击专业课程
chrome.find_element_by_xpath("/html/body/div[2]/div[2]/div/div[6]/div/a[4]/span[2]").click()
执行后效果。
接下来我们要点击一般专业类,这时候也可以发现它处于一个iframe中,同样操作点击即可。
# 通过xpath定位iframe元素
iframe = chrome.find_element_by_xpath("/html/body/div[4]/div[1]/iframe")
# 使得chrome对象聚焦于iframe,注意,switch_to后chrome将持续处于此iframe中,因此不需要多次使用switch_to
chrome.switch_to.frame(iframe)
# 点击一般专业类
chrome.find_element_by_xpath("/html/body/div[7]/div/div[3]/table/tbody/tr/td[1]/ul/li[2]/a").click()
执行后,我们就需要选择院系了,首先,老快捷键找到位置,发现是个select tag,展开后如下图所示。
select展开后有很多option,经过百度查阅资料,我们可以通过如下代码来完成选择。
# 定位选择框元素的位置
select = chrome.find_element_by_xpath("/html/body/div[7]/div/div[4]/form/ul/li[3]/select")
# 通过select tag构造一个Select对象s
s = Select(select)
# 用option tag中的value实现选择,此处选择06,即计算机学院
s.select_by_value("06")
执行之后可以看到,选择了计算机学院。
老方法点击查询按钮。
# 点击查询按钮
chrome.find_element_by_xpath("/html/body/div[7]/div/div[4]/form/ul/li[6]/div/a/span").click()
执行后可以看到很多课。
老方法实现点击选课,加个循环就可以实现实时抢课,但是每次点击选课后就会跳转到其他页面,耽误下一次点击。
于是,换一种思路,我们其实只需要在剩余人数大于0的时候点击选课即可,那么如何获取到剩余人数呢。同理,先用xpath找到其所在元素,然后根据查阅资料,发现用元素对象的text成员变量可以直接得到内容。
# 找到人数,numbers = '57/80 对外:0/2',字符串类型
numbers = chrome.find_element_by_xpath("/html/body/div[7]/div/div[6]/table/tbody/tr[2]/td[15]").text
# 对字符串找到对外剩余人数,number = 0
number = int(numbers.split(sep=':')[1].split(sep='/')[0])
之后,判断,number大于0时点击选课按钮。
if number > 0:
chrome.find_element_by_xpath("/html/body/div[7]/div/div[6]/table/tbody/tr[2]/td[1]/div/a/span").click()
至此,整个流程已经结束
代码完善
很明显上述的所有代码已经足以完成整套流程,但是为了实现对于课程剩余人数的实时监控,我们还需要用一个循环,即当number == 0时,重新点击查询按钮,最终代码如下。
# 引入selenium
# 引入chromedriver
# 引入Select用于选择
# 引入time对频率进行控制
import selenium
from selenium.webdriver import Chrome
from selenium.webdriver.support.ui import Select
import time
# 打开Chrome
chrome = Chrome()
# 打开教务系统
chrome.get("http://jwxt.buaa.edu.cn:7001/ieas2.1/welcome?falg=1")
# 通过xpath定位iframe元素
iframe = chrome.find_element_by_xpath("/html/body/iframe")
# 使得chrome对象聚焦于iframe
chrome.switch_to.frame(iframe)
# 定位用户名并输入用户名,用send_keys函数来输入
chrome.find_element_by_xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/div[1]/div/input").send_keys("123456")
# 密码
chrome.find_element_by_xpath('/html/body/div[2]/div/div[3]/div[2]/div[1]/div[3]/div/input').send_keys("******")
# 点击登录
chrome.find_element_by_xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/div[7]/input").click()
# 点击学生选课
chrome.find_element_by_xpath("/html/body/div[2]/div[1]/div[1]/div[2]/div/a[6]/div").click()
# sleep是为了等待网页动画
time.sleep(0.5)
# 点击专业课程
chrome.find_element_by_xpath("/html/body/div[2]/div[2]/div/div[6]/div/a[4]/span[2]").click()
# 通过xpath定位iframe元素
iframe = chrome.find_element_by_xpath("/html/body/div[4]/div[1]/iframe")
# 使得chrome对象聚焦于iframe,注意,switch_to后chrome将持续处于此iframe中,因此不需要多次使用switch_to
chrome.switch_to.frame(iframe)
# 点击一般专业类
chrome.find_element_by_xpath("/html/body/div[7]/div/div[3]/table/tbody/tr/td[1]/ul/li[2]/a").click()
# 定位选择框元素的位置
select = chrome.find_element_by_xpath("/html/body/div[7]/div/div[4]/form/ul/li[3]/select")
# 通过select tag构造一个Select对象s
s = Select(select)
# 用option tag中的value实现选择,此处选择06,即计算机学院
s.select_by_value("06")
flag = True
while flag:
# 点击查询按钮
chrome.find_element_by_xpath("/html/body/div[7]/div/div[4]/form/ul/li[6]/div/a/span").click()
# 找到人数,numbers = '57/80 对外:0/2',字符串类型
numbers = chrome.find_element_by_xpath("/html/body/div[7]/div/div[6]/table/tbody/tr[2]/td[15]").text
# 对字符串找到对外剩余人数,number = 0
number = int(numbers.split(sep=':')[1].split(sep='/')[0])
if number > 0:
# 点击选课按钮
chrome.find_element_by_xpath("/html/body/div[7]/div/div[6]/table/tbody/tr[2]/td[1]/div/a/span").click()
flag = False
print("Got it")
总结
这样我们就基本实现了自动选课脚本,但是在实际应用中我们可能会发现,代码跑了一会儿后就报错停了,这时我们可以不断的在出现异常的代码段加入try_expext异常处理机制来处理,使得可以继续运行下去。
另外,.py可以多开,因此实际上可以同时监控多门课程,或者对一门课程进行一秒十次甚至百次的实时监控,一有空余则会立刻抢到。
出于对于校园服务器承载能力考虑,千万不要开的过多,占用太多资源,影响大家使用。