Selenium+Python Automation
缘起
最近参加某坤的量化策略比赛。然而由于才疏学浅,写不出什么robust的代码,于是只能把alpha101上的内容看看,提取出价量的和基本面的一些思路,然后用Python暴力穷举出组合的字符串,然后用爬虫写入并读取fitness。这种做法我认为PM肯定会不大高兴,像是用一个方法绕过了相关性检验。不过没辙了,最近课业压力太大,先这样吧,如果能拿到实习再好好去研究怎么写好。
Selenium在这里的用途就是帮我把所有检验过的alpha全部提交。模拟我的鼠标点击网页操作,自动帮我登上网站,然后一行一行按submit,然后翻页循环。说实话参加比赛姿态这么蠢也略有点惭愧。
环境搭建
参考: http://www.jianshu.com/p/96bcc261b75a
简单入门
# coding = utf-8
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
browser.quit()
“# coding = utf-8” 可加可不加,防止乱码
from selenium import webdriver 把包导进来
browser = webdriver.Firefox() 操控哪个浏览器?官方是Firefox ,也可以换成Ie 或Chrome 。browser 可以随便取,但后面要用它操纵各种函数执行。
browser.find_element_by_id(“kw”).send_keys(“selenium”) 一个控件有若干属性id 、name、(也可以用其它方式定位),百度输入框的id 叫kw ,我要在输入框里输入selenium
browser.find_element_by_id(“su”).click() 搜索的按钮的id 叫su ,我需要点一下按钮( click() )。
browser.quit() 退出并关闭窗口的每一个相关的驱动程序
browser.close() 关闭当前窗口,用哪个看需求了。
元素定位
对象的定位应该是自动化测试的核心, 要想操作一个对象, 首先应该识别这个对象。 一个对象就是一个人一样,他会有各种的特征(属性) ,如比我们可以通过一个人的身 份证号,姓名,或者他住在哪个街道、楼层、门牌找到这个人。 那么一个对象也有类似的属性,我们可以通过这个属性找到这对象。 webdriver 提供了一系列的对象定位方法,常用的有以下几种: · id
· name
· class name
· link text
· partial link text
· tag name
· xpath
· css selector
id和name定位
id 和 name 是最最常用的定位方式,因为大多数控件都有这两个属性,而且 在对控件的 id 和 name 命名时一般使其有意义也会取不同的名字。 通过这两个属性使我 们找一个页面上的属性变得相当容易 我们通过前端工具,找到了百度输入框的属性信息,如下:
<input id="kw" class="s_ipt" type="text" maxlength="100" name="wd" autocomplete="off">
id=”kw” 通过 find_element_by_id(“kw”) 函数就是捕获到百度输入框 name=”wd” 通过 find_element_by_name(“wd”)函数同样也可以捕获百度输入框
tag name和class name定位
从上面的百度输入框的属性信息中,我们看到,不单单只有 id 和 name 两个属性, 比如 class 和 tag name(标签名)
<input id="kw" class="s_ipt" type="text" maxlength="100" name="wd" autocomplete="off">
<input>
input 就是一个标签的名字, 可以通过 find_element_by_tag_name(“input”) 函数来定位。 class=“s_ipt” 通过 find_element_by_class_name(“s_ipt”)函数捕获百度输入框
CSS定位
CSS(Cascading Style Sheets)是一种语言,它被用来描述 HTML 和 XML 文档的表现。 CSS 使用选择器来为页面元素绑定属性。这些选择器可以被 selenium 用作另外的定位策 略。 CSS 的比较灵活可以选择控件的任意属性,上面的例子中: find_element_by_css_selector(“#kw”) 通过 find_element_by_css_selector( )函数,选择取百度输入框的 id 属性来定义
也可以取 name 属性 新 闻 driver.find_element_by_css_selector(“a[name=\“tj_news\“]”).click()
可以取 title 属性 网页 driver.find_element_by_css_selector(“a[title=\“web\“]”).click()
也可以是取..: driver.find_element_by_css_selector(“a.RecycleBin”).click()
虽然我也没全部理解 CSS 的定位,但是看上去应该是一种非常灵活和牛X的定位方式
扩展阅读: http://www.w3.org/TR/css3-selectors/
http://www.w3school.com.cn/css/css_positioning.asp
XPath定位
什么是 XPath:http://www.w3.org/TR/xpath/ XPath 基础教程:http://www.w3schools.com/xpath/default.asp selenium 中被误解的 XPath : http://magustest.com/blog/category/webdriver/
XPath 是一种在 XML 文档中定位元素的语言。因为 HTML 可以看做 XML 的一种实现,所以 selenium 用户可是使用这种强大语言在 web 应用中定位元素。XPath 扩展了上面 id 和 name 定位方式,提供了很多种可能性,比如定位页面上的第三个多选框。
xpath:attributer (属性)
driver.find_element_by_xpath("//input[@id='kw']").send_keys("selenium")
#input 标签下 id =kw 的元素
xpath:idRelative (id 相关性)
driver.find_element_by_xpath("//div[@id='fm']/form/span/input").send_keys("selenium")
#在/form/span/input 层级标签下有个 div 标签的 id=fm 的元素
driver.find_element_by_xpath("//tr[@id='check']/td[2]").click()
# id 为'check' 的 tr ,定位它里面的第2个 td
xpath:position (位置)
driver.find_element_by_xpath("//input").send_keys("selenium")
driver.find_element_by_xpath("//tr[7]/td[2]").click()
#第7个 tr 里面的第2个 td
xpath: href (水平参考)
driver.find_element_by_xpath("//a[contains(text(),'网页')]").click()
#在 a 标签下有个文本(text)包含(contains)'网页' 的元素
xpath:link
driver.find_element_by_xpath("//a[@href='http://www.baidu.com/']").click()
#有个叫 a 的标签,他有个链接 href='http://www.baidu.com/ 的元素
link定位
有时候不是一个输入框也不是一个按钮,而是一个文字链接,我们可以通过 link
browser.find_element_by_partial_link_text(“贴”).click() #通过 find_element_by_partial_link_text() 函数,我只用了“贴”字,脚本一样找到了”贴 吧” 的链接
#coding=utf-8
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_link_text("贴 吧").click()
browser.quit()
一般一个页面上不会出现相同的文件链接,通过文字链接来定位也是一种简单有效的定位方式。
Partial link text定位
通过部分链接定位,这个有时候也会用到,我还没有想到很好的用处。拿上面的例子,我可以只用链接的一部分文字进行匹配:
browser.find_element_by_partial_link_text("贴").click()
#通过 find_element_by_partial_link_text() 函数,我只用了“贴”字,脚本一样找到了"贴 吧" 的链接
添加休眠
# coding = utf-8
from selenium import webdriver
import time #调入 time 函数
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
time.sleep(0.3) #休眠0.3秒
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3) # 休眠3秒
browser.quit()
智能等待
通过添加 implicitly_wait() 方法就可以方便的实现智能等待;implicitly_wait(30) 的用法应该比 time.sleep() 更智能,后者只能选择一个固定的时间的等待,前者可以 在一个时间范围内智能的等待。 文档解释: selenium.webdriver.remote.webdriver.implicitly_wait(time_to_wait) 隐式地等待一个无素被发现或一个命令完成;这个方法每次会话只需要调用一次 time_to_wait: 等待时间 用法: browser .implicitly_wait(30)
# coding = utf-8
from selenium import webdriver
import time #调入 time 函数
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.implicitly_wait(30) #智能等待30秒
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
browser.quit()
打印信息
打印tile
coding = utf-8
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.baidu.com')
print driver.title # 把页面title 打印出来
driver.quit()
打印URL
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
url= 'http://www.baidu.com'
#通过get 方法获取当前URL 打印
print "now access %s" %(url)
browser.get(url)
time.sleep(2)
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
设置浏览器
浏览器最大化 我们知道调用启动的浏览器不是全屏的,这样不会影响脚本的执行,但是有时候会影响我们“观看”脚本的执行。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
print "浏览器最大化"
browser.maximize_window() #将浏览器最大化显示
time.sleep(2)
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
设置浏览器宽、高
最大化还是不够灵活,能不能随意的设置浏览的宽、高显示?当然是可以的。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
browser.get("http://m.mail.10086.cn")
time.sleep(2)
#参数数字为像素点
print "设置浏览器宽480、高800显示"
browser.set_window_size(480, 800) time.sleep(3)
browser.quit()
操作浏览器的前进、后退 浏览器上有一个后退、前进按钮,对于浏览网页的人是比较方便的;对于做web 自动化测试的同学来说应该算是一个比较难模拟的问题;其实很简单,下面看看python的实现方式。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
#访问百度首页
first_url= 'http://www.baidu.com'
print "now access %s" %(first_url)
browser.get(first_url)
time.sleep(2)
#访问新闻页面
second_url='http://news.baidu.com'
print "now access %s" %(second_url)
browser.get(second_url)
time.sleep(2)
#返回(后退)到百度首页
print "back to %s "%(first_url)
browser.back()
time.sleep(1)
#前进到新闻页
print "forward to %s"%(second_url)
browser.forward()
time.sleep(2)
browser.quit()
为了使过程让你看得更清晰,在每一步操作上都加了print 和sleep 。 说实话,这两个功能平时不太常用,所能想到的场景就是几个页面来回跳转,但又不想用get url 的情况下。
操作测试对象
前面讲到了不少知识都是定位元素,定位只是第一步,定位之后需要对这个原素进行操作。鼠标点击呢还是键盘输入,这要取决于我们定位的是按钮还输入框。
一般来说,webdriver 中比较常用的操作对象的方法有下面几个
click 点击对象 send_keys 在对象上模拟按键输入 clear 清除对象的内容,如果可以的话 submit 清除对象的内容,如果可以的话 text 用于获取元素的文本信息
鼠标点击与键盘输入
在我们本系列开篇的第一个例子里就用到了到click 和send_skys ,别翻回去找了,我再贴一下代码:
coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(2)
#通过submit() 来操作
driver.find_element_by_id("su").submit()
time.sleep(3)
driver.quit()
send_keys(“xx”) 用于在一个输入框里输入xx 内容。 click() 用于点击一个按钮。 clear() 用于清除输入框的内容,比如百度输入框里默认有个“请输入关键字”的信息,再比如我们的登陆框一般默认会有“账号”“密码”这样的默认信息。 clear 可以帮助我们清除这些信息。
submit 提交表单
我们把“百度一下”的操作从click 换成submit 可以达到相同的效果:
#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(2)
#通过submit() 来操作
driver.find_element_by_id("su").submit()
time.sleep(3)
driver.quit()
text 获取元素文本 text 用于获取元素的文本信息 下面把百度首页底部的声明打印输出
#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
time.sleep(2)
#id = cp 元素的文本信息
data=driver.find_element_by_id("cp").text
print data #打印信息
time.sleep(3)
driver.quit()
输出:
>>>
©2013 Baidu 使用百度前必读京ICP 证030173号
get_attribute 获得属性值
get_attribute 获得属性值。 这个函数的用法前面已经有出现过,在定位一组元素的时候有使用到它,只是我们没有做过多的解释。 一般用法:
select = driver.find_element_by_tag_name("select")
allOptions = select.find_elements_by_tag_name("option")
for option in allOptions:
print "Value is: " + option.get_attribute("value")
option.click()
.....
键盘事件
键盘按键用法,键盘组合键用法,send_keys() 输入中文乱码问题
键盘按键用法
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.keys import Keys #需要引入keys 包
import os,time
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud.kuaibo.com%2F")
time.sleep(3)
driver.maximize_window() # 浏览器全屏显示
driver.find_element_by_id("user_name").clear()
driver.find_element_by_id("user_name").send_keys("fnngj")
#tab 的定位相相于清除了密码框的默认提示信息,等同上面的clear()
driver.find_element_by_id("user_name").send_keys(Keys.TAB)
time.sleep(3)
driver.find_element_by_id("user_pwd").send_keys("123456")
#通过定位密码框,enter(回车)来代替登陆按钮
driver.find_element_by_id("user_pwd").send_keys(Keys.ENTER)
'''
#也可定位登陆按钮,通过enter(回车)代替click()
driver.find_element_by_id("login").send_keys(Keys.ENTER)
'''
time.sleep(3)
driver.quit()
要想调用键盘按键操作需要引入keys 包: from selenium.webdriver.common.keys import Keys 通过send_keys()调用按键: send_keys(Keys.TAB) # TAB send_keys(Keys.ENTER) # 回车
注意:这个操作和页面元素的遍历顺序有关,假如当前定位在账号输入框,按键盘的tab 键后遍历的不是密码框,那就不法输入密码。假如输入密码后,还有需要填写验证码,那么回车也起不到登陆的效果。
键盘组合键用法
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
#输入框输入内容
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(3)
#ctrl+a 全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
time.sleep(3)
#ctrl+x 剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')
time.sleep(3)
#输入框重新输入内容,搜索
driver.find_element_by_id("kw").send_keys(u"91测试学堂")
driver.find_element_by_id("su").click()
time.sleep(3)
driver.quit()
上面的操作没有实际意义,但向我们演示了键盘组合按键的用法。
中文乱码问题
selenium2 python 在send_keys()中输入中文一直报错,其实前面加个小u 就解决了:
coding=utf-8
send_keys(u"输入中文")
需要注意的是utf-8并不是万能的,我们需要保持脚本、浏览器、程序三者编码之间的转换;如果utf-8不能解决,可以尝试GBK 或修改浏览器的默认编码。
鼠标事件
ActionChains 类
context_click() 右击 double_click() 双击 drag_and_drop() 拖动 测试的产品中有一个操作是右键点击文件列表会弹出一个快捷菜单,可以方便的选择快捷菜单中的选择对文件进行操作(删除、移动、重命名),之前学习元素的点击非常简单:
driver.find_element_by_id(“xxx”).click()
那么鼠标的双击、右击、拖动等是否也是这样的写法呢?例如右击:
driver.find_element_by_id(“xxx”).context_click()
经过运行脚本得到了下面的错误提示: AttributeError: ‘WebElement’ object has no attribute ‘context_click’ 提示右点方法不属于webelement 对象, 通过查找文档, 发现属于ActionChains 类,但文档中没有具体写法。
鼠标右键
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fwebcloud.kuaibo.com%2F")
#登陆快播私有云
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").send_keys("123456")
driver.find_element_by_id("dl_an_submit").click()
time.sleep(3)
#定位到要右击的元素
qqq
=driver.find_element_by_xpath("/html/body/div/div[2]/div[2]/div/div[3]/table/tbody/tr/td[2]")
#对定位到的元素执行鼠标右键操作
ActionChains(driver).context_click(qqq).perform()
#你也可以使用三行的写法,但我觉得上面两行写法更容易理解
chain = ActionChains(driver)
implement =
driver.find_element_by_xpath("/html/body/div/div[2]/div[2]/div/div[3]/table/tbody/tr/td[2]")
chain.context_click(implement).perform()
time.sleep(3) #休眠3秒
driver.close()
这里需要注意的是,在使用ActionChains 类之前,要先将包引入。 右击的操作会了,下面的其它方法比葫芦画瓢也能写出来。
鼠标双击
鼠标双击的写法:
#定位到要双击的元素
qqq =driver.find_element_by_xpath("xxx")
#对定位到的元素执行鼠标双击操作
ActionChains(driver).double_click(qqq).perform()
鼠标拖放
鼠标拖放操作的写法:
#定位元素的原位置
element = driver.find_element_by_name("source")
#定位元素要移动到的目标位置
target = driver.find_element_by_name("target")
#执行元素的移动操作
ActionChains(driver).drag_and_drop(element, target).perform()
标签页切换
如果打开多个浏览器句柄和标签页的对应关系:
标签页顺序(按照打开顺序):1 2 3 4 5
对应的句柄 :0 4 3 2 1
from selenium import webdriver
import time
browser = webdriver.Chrome()
first_url='http://www.baidu.com'
browser.find_element_by_xpath('//div/div/div/ul/li[1]/strong/a').click()
browser.switch_to_window(browser.window_handles[0])
browser.title #第一个页面
browser.switch_to_window(browser.window_handles[1])
browser.title #最后一个页面
browser.quit()
常用代码
找某元素是否存在
def isElementExist(code):
try:
browser.find_element_by_xpath(code)
return True
except:
return False
结合函数,代码里循环中,遇到一个页面,看有没有要找的那个按钮,有的话就click,没有就continue。submit是button的Xpath。
if isElementExist(submit):
browser.find_element_by_xpath(submit).click()
else:
continue
常用链接
官方文档: https://seleniumhq.github.io/selenium/docs/api/py/index.html
坑:http://www.huangbowen.net/blog/2013/06/25/practice-of-webdriver/