简单说一下为什么会想写这个小demo吧:
之前三年在南校住,约图书馆的话,一般约在新校,新校图书馆的设施条件好,开空调,而且座位多,不用担心约上约不上。大四搬来校本部了,图书馆就是之前老中南工大的图书馆,条件有点差,而且只有二楼A区会开空调,所以约的话可能有点困难。除此之外,中南大学的图书馆预约系统是每天早上六点开启的,也就是说我如果要想约到位置,理论上我六点就要起来预约,然后睡一个小时的回笼觉?偶尔这样做还可以,每天起那么早预约,谁受得了啊,尤其是对考研的同学来说。当然我不考研,也不去图书馆,所以这个小demo实际上是为了一个朋友写的,我可不想她每天起那么早就为了预约个图书馆。
所用工具
毫无疑问用python写
所用的库是selenium
浏览器是chrome
和自动操作chrome的chromedriver(chromedriver根据自己的chrome版本下载)
大致思路
自动化操作chrome浏览器,模拟鼠标操作,具体步骤如下
1.登录操作
这个是中南大学图书馆登录预约需要的一个身份验证
统一身份认证平台
这个登录界面还是很简单的,因为它不需要我们输入图片验证码!!!
如果需要图片验证码的话,就需要训练一个图片库来完成验证了,这就有点麻烦了。可能是因为图书馆预约是件很小的事情,中南大学认为没人会这么闲,还专门写个demo预约吧,哈哈。
话不多说,抓取元素(F12)。
这里查看了账号输入那个框的元素,可以看出来它的ID是独一无二的,所以就可以根据id 定位
user_name_input = browser.find_element_by_id("username")
user_name_input.send_keys(user_name)
这样的话,就可以实现自动填写用户名了,密码填写同理就行了。
登录按钮也是一个独一无二的ID,同样用上述方法定位,定位之后需要鼠标模拟点击操作,如下
login_button = browser.find_element_by_id("login_submit")
ActionChains(browser).move_to_element(login_button).click(login_button).perform()
这样就可以登录成功啦,登录跳转到如下界面
2.选择需要预约的校区
按照之前的思路想,我们还是看看每个校区下边的座位是不是独一无二可定位的。
查看元素:
新校区的
校本部的:
可以发现,class类型是完全一样的,按照我们之前的定位方法是行不通的,那到底有没有不同的地方嘞?
当然有的,仔细观察可以发现,它的这个href的值是不一样的,所以我们可以使用xpath 定位啦,这之后的定位操作也是一样的,xpath定位比较通用,只要能找到那个不同的地方就OK啦,可能是它的href,也可能是它的width之类的。
primary_button = browser.find_element_by_xpath("//*[@href='/home/web/seat/area/94']")
根据不同的量定位就只需要改变句柄里边的东西就行了。
这是我选择校本部之后的界面
3.选择需要预约的时间(明天)
可以发现哈,今天和明天两个选项卡的class是不同的,所以就可以根据这个定位啦!
PS:其实一开始我想用的是href定位,但是href里边有个日期,要用这个定位的话,免不了要用一个字符串的操作辽,当然这个操作我们之后还是会用到的,但是在这里用,可以,但没必要。
primary_button = browser.find_element_by_xpath("//*[@class='btn btn-default area_day']")
这样就可以选择预约明天啦!
选择预约明天后的界面如下:
4.选择楼层
前边的都是开胃菜,直接复制粘贴就行了,接下来的操作就有点难(实际上还是很简单)了。
按照之前的思路,我们的想法肯定是直接查看楼层的元素就行了呗,但当你这样做的时候,你会发现:
楼层是在这个整个的画布canvas上的啊,我们定位只能定位到这个canvas画布啊,定不到楼层按钮啊,那怎么办呢?
思路就是,我定位到这个画布之后,我计算出楼层按钮相对于这个画布的相对位置,然后模拟鼠标移动过去就可以啦。但是需要注意的是,浏览器窗口大小不同,分辨率不同,需要移动的距离是不一样的,这个就需要自己慢慢调试啦。当然这是个呆逼方法,还要更通用的方法,不过我觉得没必要搞那么复杂,反正就我自己用,就没用那种方法啦!
canvas = browser.find_element_by_xpath("//canvas[@width='683']")
ActionChains(browser).move_to_element(canvas).move_by_offset(300, 120).pause(2).click().perform()
这样就可以了,不同的电脑width不同,offset移动的距离也不同。
5.选择区域(二楼A区)
和4是一样的方法,这里就不赘述了
6.选择座位
到这一步就可以说是大功告成啦!
不同的座位data-no编号是不一样的,就根据这一点去定位你想要的座位就可以了,这点就友好太多了,要是还是要算offset的话,那我就猝死了。
预约之后,会跳出一个对话框来,那个对话框,你点击一下OK就行,这个简单,不说了。
具体参考了以下文章
自动疫情填报
其他
实际上,这都是理想状态下的,一次成功。
但可能你预约的过程中,出了问题,导致没约上,那岂不是完蛋了,所以还要加判断来看看是不是约上了,没约上了重新约。这部分代码仁者见仁智者见智,就看你想怎么写了,我就不献丑了。
外行看热闹,内行看笑话。我的目的就是为了让我的小伙伴不用六点起来预约,所以就是依葫芦画瓢写的,不对的地方多多包涵哈。
你还别说,就单单复制粘贴,我还搞了小几十行
最后呈现一下我的demo运行情况:
中间的报错不要在意,哈哈,反正程序能正常运行。可以看出来,我是预约了两次才成功约上的。而预约的座位不是固定的,是根据同学要求,从它的座位池里边随机选的一个,这样也可以提高预约的成功率。