缘起

最近参加某坤的量化策略比赛。然而由于才疏学浅,写不出什么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()

一般一个页面上不会出现相同的文件链接,通过文字链接来定位也是一种简单有效的定位方式。

通过部分链接定位,这个有时候也会用到,我还没有想到很好的用处。拿上面的例子,我可以只用链接的一部分文字进行匹配:

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/