qiangker


详细又简单的小白抢课教学——通过selenium配合chromedriver模拟手动操作进行抢课,以北航教务系统为例。

实现效果

大概一秒2-3次,多开的话,没有上限,一秒百次都是可能的。

环境配置

代码流程

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可以多开,因此实际上可以同时监控多门课程,或者对一门课程进行一秒十次甚至百次的实时监控,一有空余则会立刻抢到。

出于对于校园服务器承载能力考虑,千万不要开的过多,占用太多资源,影响大家使用。


文章作者: Wandy
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Wandy !
  目录