赞
踩
这学期疫情比较严重,学校一直处于封闭管理状态,去图书馆学习自然成为了大多数人的选择,尤其是考试周图书馆更是一座难求,为了能够抢到一个比较好的座位甚至需要每天早上6点半准时登录系统去预约第二天的座位。
我身边很多同学都是这样,所以我就想能不能自己写一个抢座位程序每天早上定时运行实现图书馆和睡觉自由兼得呢?答案自然是可以的。
首先为了模拟用户自动登录学校系统进行图书馆座位预约,我使用了python的Selenium。
Selenium简单来说就是一个用于网站的自动化测试工具,可以支持Chrome、Firefox和Safari等各种主流浏览器以及Windows、Linux和IOS等多种操作系统。通过将它运行在浏览器上就可以实现模拟用户的各类操作。
我使用的是Chrome浏览器,下面是对应的chromedriver下载地址(要根据自己浏览器版本选择),其他浏览器驱动大家可以自行搜索。
具体的下载安装和配置使用方法可以参考下面这篇文章。
这里是一些用到的库,需要直接pip安装就可以。
- from selenium import webdriver
- import time
- import datetime
- from selenium.webdriver.common.by import By
- from retry import retry
下面开始主要的程序编写。
第一步,根据用户登录界面对应的网页源代码进行模拟登录操作。
- driver=webdriver.Chrome()
- #登录
- driver.get('http://seat.lib.dlut.edu.cn/yanxiujian/client/login.php?redirect=index.php')
- time.sleep(2)
- name = driver.find_element(by=By.ID, value='un')
- name.send_keys('xxxxxx') #输入学号
- password = driver.find_element(by=By.ID, value='pd')
- password.send_keys('xxxxxx') #输入密码
- login = driver.find_element(by=By.CLASS_NAME, value='login_box_landing_btn')
- login.click() #点击登录按钮
之后便是根据座位预约的流程将具体操作通过selenium实现。
按照顺序分别是选换座位功能、点击下一天、选择图书馆、选择阅览室、选择并确认座位。
这里选换座位和下一天都是使用简单的button操作即可完成,直接附上代码。
- # 进入座位分配
- seat = driver.find_element(by=By.CLASS_NAME, value='btn-success')
- seat.click()
- time.sleep(1)
- # 下一天
- next_day = driver.find_element(by=By.ID, value='nextDayBtn')
- next_day.click()
其中选择图书馆和阅览室操作比较特殊,在对应网页源代码位置没有button标签,并不能直接使用click事件。这里给出了两种解决方法。
第一种是直接根据跳转之后的网页链接直接对URL进行访问。一个完整的URL包括协议、域名、端口、虚拟目录、文件名、参数和锚几个部分。其中参数部分,又称搜索部分、查询部分,是区分不同子类的关键,比如这里的图书馆选择就是根据curdate和area_id两个参数进行设计的。
- year = datetime.date.today().year
- month = datetime.date.today().month
- day = datetime.date.today().day
- format = '%d/%d/%d' % (year, month, day)
-
- # 选择伯川图书馆
- driver.get("http://seat.lib.dlut.edu.cn/yanxiujian/client/roomSelectSeat.php?curdate=" + format + "&area_id=17")
- time.sleep(1)
第二种是在定位的元素上执行JS操作。这种方法很多时候都会使用到,这里具体介绍一下。执行JS代码进行操作元素的情况有以下几种:
- 元素是使用JS写的
- 元素为不可见状态
- 元素为不能点击状态
- 修改元素属性(WebDriver没有提供对应的接口方法)
- 浏览器滚动条(WebDriver没有提供对应的接口方法)
具体的执行JS方法分为execute_script(同步请求执行)和execute_async_script(异步请求执行),同步执行需要等待服务器返回请求结果后才能进行后续操作,而异步则不需要。选择阅览室就是采用的这种方法,并且由于操作后需要等待弹窗出现才能进行之后的座位选择,这里使用的是execute_script的JS执行方法。
- # 选择阅览室
- js = 'document.getElementsByClassName("blue")[6].click();'
- driver.execute_script(js)
- time.sleep(2)
选座模式有自动分配和手动选择两种button可供点击。选择自动分配会弹出系统随机分配的预约界面,之后点击确定button即可。手动选择会跳转到座位分布界面可以自由选择座位。
具体的座位选择需要考虑两个因素:位置(第几排第几个)和占用情况(红色表示占用,绿色表示空闲)。
其中特定位置的定位使用了CSS选择器的方法,querySelector()返回匹配的第一个元素,querySelectorAll()返回所有匹配元素。
注:CSS选择器里面的匹配内容标签属性不是常用的id或class,使用过程中要注意字符串引号的处理。
- # 选择座位
- style = "[style~='#B9DEA0']"
- index = "[data-index='1']"
- js_seat = "document.querySelector(\"" + index + "\").querySelectorAll(\"" + style + "\")[0].click();"
- driver.execute_script(js_seat)
- time.sleep(1)
- # 确认座位
- verify = driver.find_element(by=By.ID, value='btn_submit_addorder')
- verify.click()
因为selenium的操作速度并不是很快,所以为了保证即使抢不到理想座位也有座位可以自习,还加入了异常处理部分,即在尝试两次手动选择座位都失败之后返回到上一个界面进行座位自动分配实现快速预约。
- # 选择座位
- style = "[style~='#B9DEA0']"
- try:
- index = "[data-index='1']"
- js_seat = "document.querySelector(\"" + index + "\").querySelectorAll(\"" + style + "\")[0].click();"
- driver.execute_script(js_seat)
- time.sleep(1)
- except:
- try:
- index = "[data-index='7']"
- js_seat = "document.querySelector(\"" + index + "\").querySelectorAll(\"" + style + "\")[0].click();"
- driver.execute_script(js_seat)
- time.sleep(1)
- except:
- # 返回并随机分配座位
- back = driver.find_element(by=By.ID, value='btnBack')
- back.click()
- time.sleep(1)
- js = 'document.getElementsByClassName("blue")[6].click();'
- driver.execute_script(js)
- time.sleep(1)
- match = driver.find_elements(by=By.CSS_SELECTOR, value="[class~='btn-primary']")[2]
- match.click()
- time.sleep(1)
- # 确认座位
- verify = driver.find_element(by=By.ID, value='btn_submit_addorder')
- verify.click()
除此之外,在测试过程中为避免服务器响应较慢、网络延迟座位确认失败等问题导致抢座失败,代码中使用了retry模块进行回调重试并对主体部分进行了循环执行,核心代码如下(图书馆、阅览室和座位可根据需求自己更改):
- @retry(tries=3, delay=1)
- def run():
- driver.get('http://seat.lib.dlut.edu.cn/yanxiujian/client/index.php')
- time.sleep(1)
- # 进入座位分配
- seat = driver.find_element(by=By.CLASS_NAME, value='btn-success')
- seat.click()
- time.sleep(1)
- # 下一天
- next_day = driver.find_element(by=By.ID, value='nextDayBtn')
- next_day.click()
- # 选择伯川图书馆
- driver.get("http://seat.lib.dlut.edu.cn/yanxiujian/client/roomSelectSeat.php?curdate=" + format + "&area_id=17")
- time.sleep(1)
- # 选择阅览室
- js = 'document.getElementsByClassName("blue")[2].click();'
- driver.execute_script(js)
- time.sleep(1)
- # 手动选择
- match = driver.find_element(by=By.CSS_SELECTOR, value="[class~='btn-success']")
- match.click()
- time.sleep(1)
- # 选择座位
- style = "[style~='#B9DEA0']"
- try:
- index = "[data-index='9']"
- js_seat = "document.querySelector(\"" + index + "\").querySelectorAll(\"" + style + "\")[0].click();"
- driver.execute_script(js_seat)
- time.sleep(1)
- except:
- try:
- index = "[data-index='13']"
- js_seat = "document.querySelector(\"" + index + "\").querySelectorAll(\"" + style + "\")[0].click();"
- driver.execute_script(js_seat)
- time.sleep(1)
- except:
- # 返回并随机分配座位
- back = driver.find_element(by=By.ID, value='btnBack')
- back.click()
- time.sleep(1)
- js = 'document.getElementsByClassName("blue")[2].click();'
- driver.execute_script(js)
- time.sleep(1)
- match = driver.find_elements(by=By.CSS_SELECTOR, value="[class~='btn-primary']")[2]
- match.click()
- time.sleep(1)
- # 确认座位
- verify = driver.find_element(by=By.ID, value='btn_submit_addorder')
- verify.click()
-
- for i in range(3):
- run()
- time.sleep(2)
这样,自动抢图书馆座位便已经成功实现。至于定时运行,可以选择windows自带的任务计划程序系统工具,创建任务、添加python脚本、设置好启动时间就可以睡觉醒来直接去图书馆啦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。