selenium,一个有效的自动化测试工具,我主要介绍下关于如何封装WebDriver,为一个比较轻松上手的自动化测试埋下铺垫
工具/原料
selenium-server-standalone-2390jar软件包
方法/步骤
先了解下什么是WebDriver
熟悉WebDriver的关于JAVA的一些API的使用
介绍一个火狐的插件firepath
我做的自动化测试是在火狐上运行的,因为我找到一个对于自动化测试比较有帮助的插件,那就是firepath,具体用法,就是先安装该插件,它会在firebug那么调试的窗口最右边出现。firepath截图和firepath安装后的截图如下所示。(优点:点哪个元素,哪个元素的xpath路径立马显示,看图吧)
自己封装的WebDriver的API方法
package comqiangdata;
import javautilIterator;
import javautilList;
import javautilSet;
import orgopenqaseleniumBy;
import orgopenqaseleniumNoSuchElementException;
import orgopenqaseleniumWebDriver;
import orgopenqaseleniumWebElement;
/
WebDriver帮助类
/
public class WebDriverUtil {
/
写在前面的话:
我写的这个WebDriver帮助类法仅仅针对于xpath访问的
为什么这么写呢?有两点理由
其一:xpath获取方便,我用的是firefox浏览器,只要用firepath这个插件,我们就可以正确的定位到每一个节点,并且firepath支持查询功能,值得大家使用
其二:使用统一的xpath,给编码带来了一定的规范
/
/
没有验证码的的登录
@param wd WebDriver对象
@param unameXpath 用户名的xpath路径
@param uname 用户名
@param pwdXpath 密码xpath路径
@param pwdValue 密码
@param loginBtnXpath 登录按钮xpath
/
public static void login(WebDriver wd,String url,String unameXpath,String uname,String pwdXpath,String pwd,String loginBtnXpath){
wdget(url);
inputs(wd,unameXpath,uname);
inputs(wd,pwdXpath, pwd);
click(wd,loginBtnXpath);
}
/
登录可能放在一个frame里了:我是因为遇到过,所以才加了个方法的
@param wd WebDriver对象
@param unameXpath 用户名的xpath路径
@param uname 用户名
@param pwdXpath 密码xpath路径
@param pwdValue 密码
@param loginBtnXpath 登录按钮xpath
@param frame 第几个框架
/
public static void loginFrame(WebDriver wd,String url,String unameXpath,String uname,String pwdXpath,String pwd,String loginBtnXpath,int frame){
wdget(url);
wdswitchTo()frame(frame);
inputs(wd,unameXpath,uname);
inputs(wd,pwdXpath, pwd);
click(wd,loginBtnXpath);
}
/
有验证码的登录
@param wd WebDriver对象
@param unameXpath 用户名的xpath路径
@param uname 用户名
@param pwdXpath 密码xpath路径
@param pwdValue 密码
@param loginBtnXpath 登录按钮xpath
@param seconds 输入验证码的间隔
/
public static void loginVerify(WebDriver wd,String url,String unameXpath,String uname,String pwdXpath,String pwd,String loginBtnXpath,int seconds){
wdget(url);
inputs(wd,unameXpath,uname);
inputs(wd,pwdXpath, pwd);
try {
Threadsleep(seconds1000); //这段时间内请输入验证码
} catch (InterruptedException e) {
eprintStackTrace();
}
click(wd,loginBtnXpath);
}
/
获取页面单个元素
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static WebElement getElement(WebDriver wd,String xpath){
return wdfindElement(Byxpath(xpath));
}
/
获取页面的一组元素
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static List<WebElement> getElements(WebDriver wd,String xpath){
return wdfindElements(Byxpath(xpath));
}
/
获取元素节点的文本值
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static String getText(WebDriver wd,String xpath){
return wdfindElement(Byxpath(xpath))getText();
}
/
获取元素节点的文本值
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return 没有找到该元素时会有个提示,并且不会报错,建议使用
/
public static String getExistText(WebDriver wd,String xpath){
if(isExist(wd, xpath)){
return getText(wd, xpath);
}
return "-1";
}
/
获取元素节点的属性值
@param wd WebDriver对象
@param xpath 目标节点的xpath
@attribute 要获取目标节点的哪个属性
@return
/
public static String getAttribute(WebDriver wd,String xpath,String attribute){
return wdfindElement(Byxpath(xpath))getAttribute(attribute);
}
/
点击节点
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static void click(WebDriver wd,String xpath){
wdfindElement(Byxpath(xpath))click();
}
/
输入文本
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static void inputs(WebDriver wd,String xpath,String value){
wdfindElement(Byxpath(xpath))sendKeys(value);
}
/
判断是否选中
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static boolean isChecked(WebDriver wd,String xpath){
return wdfindElement(Byxpath(xpath))isSelected();
}
/
判断是否可用
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static boolean isEnabled(WebDriver wd,String xpath){
return wdfindElement(Byxpath(xpath))isEnabled();
}
/
判断是否存在元素
@param wd WebDriver对象
@param xpath 目标节点的xpath
@return
/
public static boolean isExist(WebDriver wd,String xpath){
try{
wdfindElement(Byxpath(xpath));
return true;
}catch (NoSuchElementException e) {
return false;
}
}
/
选中复选框,其实和点击一样,只是重新起了个名字
@param wd WebDriver对象
@param xpath 目标节点的xpath
/
public static void check(WebDriver wd,String xpath){
click(wd, xpath);
}
/
点击那种隐藏的下拉框
@param wd WebDriver对象
@param xpath1 事件源节点的xpath
@param xpath2 目标节点的xpath
/
public static void clickHidden(WebDriver wd,String xpath1,String xpath2){
click(wd, xpath1);
click(wd, xpath2);
}
/
获取隐藏的文本,原理同上
@param wd WebDriver对象
@param xpath1 事件源节点的xpath
@param xpath2 目标节点的xpath
/
public static void getHiddenText(WebDriver wd,String xpath1,String xpath2){
click(wd, xpath1);
getText(wd, xpath2);
}
/
获取隐藏节点的属性值
@param wd WebDriver对象
@param xpath1 事件源节点的xpath
@param xpath2 目标节点的xpath
@param attribute 要获取目标节点的哪个属性
/
public static String getHiddenAttribute(WebDriver wd,String xpath1,String xpath2,String attribute){
click(wd, xpath1);
return getAttribute(wd, xpath2, attribute);
}
/
切换窗口
@param wd WebDriver对象
@param title 要切换窗口的标题
/
public static void changeWindow(WebDriver wd,String title){
String current = wdgetWindowHandle();
Set<String> all = wdgetWindowHandles();
Iterator<String> iterator = alliterator();
while (iteratorhasNext()) {
String handle = iteratornext();
if(handleequals(current)){
continue;
}
else{
wdswitchTo()window(handle);
if(wdgetTitle()contains(title)){
Systemoutprintln("窗口成功跳转");
break;
}
else{
continue;
}
}
}
}
}
5
个人小结
以上基于WebDriver简单的封装在一定程度上可以减少代码量,封装得太少,看到的你根据自己的需要进行扩充吧,我个人特点是喜欢封装一切可以复用的代码,以便达到高效率的编码,并不是说会编码就够了,多总结总结还是会让自己的编码路不会走的那么崎岖些
获取标签内容
使用elementattribute()方法获取dom元素的内容,如:
dr = driverfind_element_by_id('tooltip')
drget_attribute('data-original-title') #获取tooltip的内容
drtext #获取该链接的text
获取标签属性
link=drfind_element_by_id('tooltip')
linkvalue_of_css_property('color') #获取tooltip的CSS属性color的属性值
linkfind_element_by_tag_name('h3')value_of_css_property('font') #获取h3的CSS属性font的属性值
获取标签状态
是否显示:使用elementis_displayed()方法
是否存在:使用find_element_by_xxx()方法,捕获其抛出的异常, 如果存在异常的话则可以确定该元素不存在
text_field=drfind_element_by_name('user')is_enabled()
#直接用elementis_enabled()方法判断button,返回值为true,因为button是使用CSS方法判断是否有效这并不是真正的方法,需要判断其class中是否有值为disabled来判断是否真正处于disabled的状态
drfind_element_by_class_name('btn')is_enabled()
是否被选中:一般判断表单元素,如radio或checkbox是否被选中,使用elementis_selected()方法
radiois_selected() #判断是否被选中
try:
drfind_element_by_id('none')
except:
print 'element does not exist'
是否有效:即是否为灰化状态,使用elementis_enabled()状态
print text_fieldis_displayed() #判断是否显示
使用时先安装 lxml 包
开始使用 #
和beautifulsoup类似,首先我们需要得到一个文档树
把文本转换成一个文档树对象
from lxml import etreeif __name__ == '__main__':doc='''
把文件转换成一个文档树对象
fromlxmlimportetree# 读取外部文件 indexhtmlhtml = etreeparse('/indexhtml')result = etreetostring(html, pretty_print=True)#pretty_print=True 会格式化输出print(result)
均会打印出文档内容
节点、元素、属性、内容 #
xpath 的思想是通过 路径表达 去寻找节点。节点包括元素,属性,和内容
元素举例
html --->div --->
这里我们可以看到,这里的元素和html中的标签一个意思。单独的元素是无法表达一个路径的,所以单独的元素不能独立使用
路径表达式 #
/ 根节点,节点分隔符,// 任意位置 当前节点 父级节点@ 属性
通配符 #
任意元素@ 任意属性node() 任意子节点(元素,属性,内容)
谓语 #
使用中括号来限定元素,称为谓语
//a[n] n为大于零的整数,代表子元素排在第n个位置的 元素//a[last()] last() 代表子元素排在最后个位置的 元素//a[last()-] 和上面同理,代表倒数第二个//a[position()<3] 位置序号小于3,也就是前两个,这里我们可以看出xpath中的序列是从1开始//a[@href] 拥有href的 元素//a[@href='内置很多函数。更多函数查看 >
Python 中可以进行网页解析的库有很多,常见的有 BeautifulSoup 和 lxml 等。在网上玩爬虫的文章通常都是介绍 BeautifulSoup 这个库,我平常也是常用这个库,最近用 Xpath 用得比较多,使用 BeautifulSoup 就不大习惯,很久之前就知道 Reitz 大神出了一个叫 Requests-HTML 的库,一直没有兴趣看,这回可算歹着机会用一下了。
使用 pip install requests-html 安装,上手和 Reitz 的其他库一样,轻松简单:
这个库是在 requests 库上实现的,r 得到的结果是 Response 对象下面的一个子类,多个一个 html 的属性。所以 requests 库的响应对象可以进行什么 *** 作,这个 r 也都可以。如果需要解析网页,直接获取响应对象的 html 属性:
不得不膜拜 Reitz 大神太会组装技术了。实际上 HTMLSession 是继承自 requestsSession 这个核心类,然后将 requestsSession 类里的 requests 方法改写,返回自己的一个 HTMLResponse 对象,这个类又是继承自 requestsResponse,只是多加了一个 _from_response 的方法来构造实例:
之后在 HTMLResponse 里定义属性方法 html,就可以通过 html 属性访问了,实现也就是组装 PyQuery 来干。核心的解析类也大多是使用 PyQuery 和 lxml 来做解析,简化了名称,挺讨巧的。
元素定位可以选择两种方式:
方法名非常简单,符合 Python 优雅的风格,这里不妨对这两种方式简单的说明:
定位到元素以后势必要获取元素里面的内容和属性相关数据,获取文本:
获取元素的属性:
还可以通过模式来匹配对应的内容:
这个功能看起来比较鸡肋,可以深入研究优化一下,说不定能在 github 上混个提交。
除了一些基础 *** 作,这个库还提供了一些人性化的 *** 作。比如一键获取网页的所有超链接,这对于整站爬虫应该是个福音,URL 管理比较方便:
内容页面通常都是分页的,一次抓取不了太多,这个库可以获取分页信息:
结果如下:
通过迭代器实现了智能发现分页,这个迭代器里面会用一个叫 _next 的方法,贴一段源码感受下:
通过查找 a 标签里面是否含有指定的文本来判断是不是有下一页,通常我们的下一页都会通过 下一页 或者 加载更多 来引导,他就是利用这个标志来进行判断。默认的以列表形式存在全局: ['next','more','older'] 。我个人认为这种方式非常不灵活,几乎没有扩展性。 感兴趣的可以往 github 上提交代码优化。
也许是考虑到了现在 js 的一些异步加载,这个库支持 js 运行时,官方说明如下:
使用非常简单,直接调用以下方法:
第一次使用的时候会下载 Chromium,不过国内你懂的,自己想办法去下吧,就不要等它自己下载了。render 函数可以使用 js 脚本来 *** 作页面,滚动 *** 作单独做了参数。这对于上拉加载等新式页面是非常友好的。
首先,你一定用过魔术方法,也一定见过魔术方法。以下划线开头的方法,比如:
这些被统称为魔术方法。
给整数和字符串做加法:
我们写个表示城市的类,它有两个属性:城市名和人口。
然后我们给两个城市做加法,发现不能相加:
报错是说City不支持"+"号,如何让它支持"+"呢?需要给类加上魔术方法__add__就可以相加了。
我们给City添加一个__add__的方法,城市相加,人口相加,创建一个新的城市:
这说明__add__有一定的魔力,当我们用到加号"+"时,python就回去寻找这个方法,如果这个对象没有这个方法就会报错。
python中,所有的运算符都是通过魔术方法来实现的。
如果我们在City类有以下方法,就可以做加减乘除了:
我们再来打印int和str查看他们的方法,int有加减乘除,str只有__add__ __mul__,它只能做加法和乘法:
列表为什么能获取元素, __getitem__,可以再任何一个类里加上这个方法,然后也就可以用[]方括号来获取元素:
我们使用最多的方法一定是__new__和__init__, 在新建方法的时候,都会调用到这两个方法:
不止有魔术方法,还有魔术属性,形如"__yyy__",通常是python自动设置的属性,我们可以使用这些属性,比如:
什么使用str方法,什么时候用repr方法?
如果我们想让print打印出来好看,可以定义__str__的方法:
这里有各种策略用于定位网页中的元素(locate elements),你可以选择最适合的方案,Selenium提供了一下方法来定义一个页面中的元素:
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
下面是查找多个元素(这些方法将返回一个列表):find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
除了上面给出的公共方法,这里也有两个在页面对象定位器有用的私有方法。这两个私有方法是find_element和find_elements。
常用方法是通过xpath相对路径进行定位,同时CSS也是比较好的方法。举例:
[html] view plain copy
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
定位username元素的方法如下:[python] view plain copy
username = driverfind_element_by_xpath("//form[input/@name='username']")
username = driverfind_element_by_xpath("//form[@id='loginForm']/input[1]")
username = driverfind_element_by_xpath("//input[@name='username']")
[1] 第一个form元素通过一个input子元素,name属性和值为username实现[2] 通过id=loginForm值的form元素找到第一个input子元素
[3] 属性名为name且值为username的第一个input元素
二 *** 作元素方法
在讲述完定位对象(locate elements)之后我们需要对该已定位对象进行 *** 作,通常所有的 *** 作与页面交互都将通过WebElement接口,常见的 *** 作元素方法如下:
clear 清除元素的内容
send_keys 模拟按键输入
click 点击元素
submit 提交表单
举例自动访问FireFox浏览器自动登录163邮箱。
[python] view plain copy
from selenium import webdriver
from seleniumwebdrivercommonkeys import Keys
import time
# Login 163 email
driver = webdriverFirefox()
driverget("")
elem_user = driverfind_element_by_name("username")
elem_userclear
elem_usersend_keys("15201615157")
elem_pwd = driverfind_element_by_name("password")
elem_pwdclear
elem_pwdsend_keys("")
elem_pwdsend_keys(KeysRETURN)
#driverfind_element_by_id("loginBtn")click()
#driverfind_element_by_id("loginBtn")submit()
timesleep(5)
assert "baidu" in drivertitle
driverclose()
driverquit()
首先通过name定位用户名和密码,再调用方法clear()清除输入框默认内容,如“请输入密码”等提示,通过send_keys("")输入正确的用户名和密码,最后通过click()点击登录按钮或send_keys(KeysRETURN)相当于回车登录,submit()提交表单。PS:如果需要输入中文,防止编码错误使用send_keys(u"中文用户名")。
三 WebElement接口获取值
通过WebElement接口可以获取常用的值,这些值同样非常重要。
size 获取元素的尺寸
text 获取元素的文本
get_attribute(name) 获取属性值
location 获取元素坐标,先找到要获取的元素,再调用该方法
page_source 返回页面源码
drivertitle 返回页面标题
current_url 获取当前页面的URL
is_displayed() 设置该元素是否可见
is_enabled() 判断元素是否被使用
is_selected() 判断元素是否被选中
tag_name 返回元素的tagName
数组允许进行批量 *** 作而无需使用for循环,因此更加简便,这种特性也被称为向量化。任何两个等尺寸之间的算术 *** 作都应用逐元素 *** 作的方式进行。
同尺度数组之间的比较,会产生一个布尔型数组。
上述 *** 作均是在同尺度数组之间进行的,对于不同尺度数组间的 *** 作,会使用到广播特性。
索引:获取数组中特定位置元素的过程;
切片:获取数组元素子集的过程。
new_a = aastype(new_type)
astype()方法一定会创建新的数组(原始数据的一个拷贝),即使两个类型一致。
ls = atolist()
转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。
数组拥有 transpose 方法,也有特殊的 T 属性。
对于更高纬度的数组, transpose 方法可以接受包含轴编号的元组,用于转置轴。
ndarray的 swapaxes 方法,通过接受一对轴编号作为参数,并对轴进行调整用于重组数据。
swapaxes 方法返回的是数据的视图,而没有对数据进行复制。
Reference:
《Python for Data Analysis:Data Wrangling with Pandas,Numpy,and IPython》
以上就是关于python怎么定位富文框textarea的元素我用xpath定位包找不到元素全部的内容,包括:python怎么定位富文框textarea的元素我用xpath定位包找不到元素、python+selenium怎么遍历一个网页中class相同的值、python使用xpath(超详细)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)