运维人员烦恼的开始


你曾经是否有这样的境遇:日常运维的一个WEB平台,每天都要进行一些繁琐的操作,需要你用鼠标键盘不停的去点点点,有时候这些操作是高度重复的,或者是零零碎碎的分散时间需要你去操作。就拿监控工具zabbix的维护期来说(zabbix是再常见不过的监控工具了),遇到公司各大平台变更集中的时间段,每个平台负责人都会向你提出维护期申请,最令人烦恼的是,不同的申请人提出的时间不同、平台不同。于是你从早到晚的加了上百个维护期,怕自己加错了还把每个维护期检查了一遍,手点的都抽筋了,脑子也很混沌了,抬头一看表晚上七点,一天就加了点维护期,领导又要批评自己了。这时候有人会说:”用zabbix-API添加维护期啊,写写python不就可以自动加了吗!”奈何自己技术糙,又不想看全是文英并且传参很麻烦的API文档,甚至某些场景你都没有API的详细说明!!那怎么办呢?使用Selenium吧!

首先看一下Selenium的效果:

玩转Selenium——Web页面自动化实战_java

引用官网的一句话:"Selenium测试直接运行在浏览器中,就像真正的用户在操作一样"。是啊,如果用selenium帮你干这些活,那你可以去腾出更多的时间去学习与工作。其实上面的过程放在代码里,主要就是分为三步走:

首先需要打开一个你想操作的网页,然后再选定该网页上的HTML元素,再对该元素进行一些列操作,做好这三步,就可以做出上面动图的效果!


支持的开发环境


语言:C、java、ruby、python、JS或者是C#

平台:linux、windows、MAC

浏览器:ie、Firefox、Safari、Opera、Chrome

所以,拿你常用的语言,常用的浏览器去开发调试,没有太大的限制条件(本文将用python +Chrome进行示范)。


First-快速上手


  1. 通过pip install selenium安装。

  2. 下载Chrome对应版本的WebDriver( 点击下方阅读原文即可跳转

  3. 编写代码:







from selenium import webdriverimport time

if __name__ == '__main__':    chrome_driver = 'C:\\xxx\\Google\\Chrome\\Application\\chromedriver.exe'  # chromedriver的文件位置    driver = webdriver.Chrome(executable_path=chrome_driver)    driver.get('https://www.baidu.com')    driver.find_element_by_id('kw').send_keys('Hello,')    time.sleep(1) # 为了方便展示加了点延迟    driver.find_element_by_id('kw').send_keys('光大科技')driver.find_element_by_id("su").click()
玩转Selenium——Web页面自动化实战_java_02

通过上述简单的插件安装与几行python代码,就实现了自动打开“百度”,输入”Hello,光大科技“,并点击搜索的功能,是不是简洁至极!值得一提的是,这是Selenium的有操作界面启动模式,即可以看到它执行过程中的操作页面,点击了哪里都可以看到。但是我们大部分Linux服务器可是没有操作界面的呀!是的,还有一种模式叫Headless启动模式,可以在不打开浏览器的前提下,使用所有Chrome支持的特性运行你的程序。相比于现代浏览器,Headless Chrome更加方便测试web应用,获得网站的截图,做爬虫抓取信息等。相比于较早的PhantomJS、SlimerJS等,Headless Chrome则更加贴近浏览器环境。


Second-元素定位


看完上面的快速开始,可能你还不知道,为什么代码可以执行输入、搜索这些功能。其实这都归功于元素的定位,并对定位后的元素进行一些操作执行,就例如上面的:



driver.find_element_by_id('kw')driver.find_element_by_id("su")

选择id为"kw"与"su"的元素,百度搜索首页HTML内容如下:

玩转Selenium——Web页面自动化实战_java_03

其实就是通过选定HTML上的元素ID “kw”(即百度搜索输入框input),然后再输入了“光大科技”这个String。熟悉前端的开发人员应该对HTML的元素并不陌生,老牌劲旅JQuery中就有常用的元素选择器,如ID选择器$("#id"),类选择器$(".className")等等,find_element_by_id('kw')就是通过选择ID元素来进行元素定位的。这时前端开发的同学又要说了:“JQuery我早就不用了!现在都用火爆的三大框架,网页哪有那么多元素绑定ID?”。是的,但是不要慌,webdriver提供了很多元素定位方法,不只是绑定ID:

id定位:find_element_by_id()

name定位:find_element_by_name()

class定位:find_element_by_class_name()

link定位:find_element_by_link_text()

partial link定位:find_element_by_partial_link_text()

tag定位:find_element_by_tag_name()

xpath定位:find_element_by_xpath()

css定位:find_element_by_css_selector()

id、name、class这些就不用多说了,直接选定就可以用。link定位,此种方法是专门用来定位文本链接的,比如百度首页右上角有“新闻”,“hao123”,“地图”等链接。如果懂HTML知识,我们就知道HTML是通过tag来定义功能的,比如input是输入,table是表格,等等。每个元素其实就是一个tag,一个tag往往用来定义一类功能,我们查看百度首页的html代码,可以看到有很多div、input、a等tag,所以很难通过tag去区分不同的元素,这个不常用。其中,个人认为功能最强大的是xpath定位,find_element_by_xpath(),它是基于HTML文档目录结构进行元素定位的(html的DOM树),理论上可以通过路径、索引、属性值、轴定位、文本test定位到几乎全部的元素,听起来就很强,但是用法也相对其他方法复杂一点点,且要具备HTML DOM的知识,举几个常用的例子如下:

多元素属性值定位(相对路径):xpath= "//标签名[@type='XX' and @name='XX']" (type、name均为属性名)

绝对路径定位:xpath = " /html/body/div/标签名[@属性="属性值"]"(定位到body下的某个div下的元素,如果div很多,可以通过div[@属性值="xx"]来具体到某个div),但是绝对路径方法维护成本太高,一般不用

test()文本定位:xpath = "//标签名[text()='上一步']"

索引定位:xpath = "//标签名[2]"如 //input[2]定位到body中第三个input标签

轴定位:用::表示,选择当前节点的父节点(parent)、子节点(child)、祖先节点(ancestor)、子孙节点(descendant)、后节点(following)前节点(preceding)、后兄弟节点(following-sibling)、前兄弟节点(preceding-sibling)xpath="//标签/关系关键字::标签",如//div[1]/child::img,就是寻找div[1]的子节点img

Xpath方法还是需要多用,多见见复杂的html dom结构,在实战中提升使用技巧,对于定位而言它几乎是万能的,有兴趣的同学可以仔细研究研究~

html dom树结构参考

- 左右滑动查看更多 -

玩转Selenium——Web页面自动化实战_java_04玩转Selenium——Web页面自动化实战_java_05

图片来源于网络


third-操作方法


通过上面的元素定位,现在同学们已经可以随心所欲的定位自己想要的元素了,那接下来就应该对所取元素进行一些快乐的操作!就如开始的demo中:



driver.find_element_by_id('kw').send_keys('Hello,')driver.find_element_by_id("su").click()

上面.send_keys().click()就是响应的元素操作,对你选中的元素进行传值、点击等等。

总结了一下相关操作方法,以百度搜索首页为例,进行操作:


driver.find_element_by_name('wd').send_keys(‘PythonSelenium’),#在百度文本搜索框内输入内容Python Seleniumdriver.find_element_by_name('wd').clear(),#清空文本搜索框的所有内容driver.find_element_by_id('su').click(),#点击搜索按钮driver.find_element_by_id('su').submit(),#提交搜索按钮,这里效果同点击搜索按钮driver.find_element_by_id('kw').size,#获取搜索框的大小driver.find_element_by_id('jgwab').text,#获取控件id为’jgwab’所显示的内容driver.find_element_by_id('su').get_attribute('type'),#获取控件id为’su’的属性,例如button,radio等driver.find_element_by_name('wd').is_displayed(),#判断搜索文本框当前是否被显示

当然也不只有简单的点点点,只要是日常操作鼠标键盘能实现的(模拟键鼠操作),Selenium都可以实现,举例如下:


driver.find_element_by_id('kw').send_keys(Keys.BACK_SPACE)#Backspace键driver.find_element_by_id('kw').send_keys(Keys.SPACE)#Space键driver.find_element_by_id('kw').send_keys(Keys.DELETE)#Delete键driver.find_element_by_id('kw').send_keys(Keys.CONTROL,'a')# CTRL + AActionChains(driver).context_click(driver.find_element_by_id('kw')).perform()#在搜索文本框利用context_click()进行鼠标右击,perform()是执行方法的语句ActionChains(driver).double_click(driver.find_element_by_id('kw')).perform()#在搜索文本框利用double_click()进行双击, perform()是执行方法的语句ActionChains(driver).drag_and_drop(driver.find_element_by_id('kw'),driver.find_element_by_id('su')).perform()#利用drag_and_drop(source,target)从搜索文本框移动到点击按钮,perform()是执行方法的语句

这些都是一些常用且实用的操作,相信你一定会用到!想了解更高阶玩法的小伙伴们可以自行学习~


The end-打包、使用


当你按照三步走写完你的python代码,并且运行正常,就可以执行打包.exe操作了。打包成.exe你的程序将可以在任何一台windos-pc上运行,可以发给你工作上的小伙伴,且不需要它本地安装任何依赖。(当然如果不嫌麻烦,在要执行的机器上安装好所有依赖,也可以用xxxx.py直接执行)安装打包工具pyinstaller:

玩转Selenium——Web页面自动化实战_java_06

执行打包命令:pyinstaller -F xxx.py(xxx.py,打包的文件),生成的exe在/项目地址/dist目录下。然后,双击,运行!


Selenium 相关其他玩法


Selenium玩爬虫


既然能选定元素并操作元素,那一定可以做爬虫吧!没错,它确实具备很多玩爬虫的优点:对比于requests玩爬虫来讲,Selenium能获取js动态给出的源码,且做到模拟真实登录减少了反爬的限制。但是缺点很明显,获得多出来的前端渲染功能是要付出代价的,requests直接不启动浏览器、不渲染动态页面,想要单位时间内爬取大量信息,性能会差很多!有时候两者结合面对反爬应该更好用一些~


Selenium IDE


它是一款依赖于Firefox浏览器的插件(xpi),可以实现脚本的录制、回放以及编辑脚本功能,元素定位等,可以利用 selenium IDE将录制的脚本生成相应的带单元测试框架的自动化测试脚本。如果只用于web自动化测试,这是一个很便捷的工具,它的页面如下。

玩转Selenium——Web页面自动化实战_java_07


调用JS语言


Selenium方法execute_script(script, *args),参数可以填写任何JavaScript语言,例如我们前端常用的alert()。浏览器滚动条的拖动,不能依靠WebDriver提供的API来实现,所以可以调用js中的window.scrollTo(xx,xx)来设置滚动条的位置。


其实Selenium+webdriver是为自动化测试web应用而生,但是我认为可以应用的场景很多,比如在不知道或不熟悉后端API情况下自动化的平台运维(本文举例),日常生活工作中高重复度、浪费时间的网页操作,都可以使用,有时候你也可以用它来抢折扣票、火车票等。当然为了更好的操作web,有时候可能还需要结合本地文件(比如excel,import xlrd),这样你就可以把每次需要填写的内容写在Excel中,随时修改,让python帮你完成相应的解析并输出。