Selenium 如何免 iframe 切换

环境搭一半就放弃 · October 17, 2018 · Last by 我问问 replied at November 19, 2018 · Last modified by admin 恒温 · 2488 hits

iframe,切换来切换去,烦死了!

看到这篇文章就算赚到!里面就有解决整天切换iframe的方法。
我们公司已经开发了3年的WEB UI自动化测试框架,但是iframe的切换至今是痛点,遇见iframe得一层层切换,早在去年本人就提出有没办法去掉iframe切换,脚本直接写各种xpath即可。
所以本文的重点(因为有同学不晓得本文重点是什么)是如何在自动化测试脚本中,不再出现driver.switchTo().frame(i);、driver.switchTo().defaultContent();、driver.switchTo().parentFrame()这些语句,因为如果要切换框架,写脚本的同学得对着iframe一个个去数或者写iframe的xpath,还得切换做切换回默认框架,父框架等脚本,非常不方便!如果在日常工作中,你不知道iframe是什么,也没有碰到iframe那就不需要看这篇文章了
首先我们公司的框架是使用JAVA的,解决iframe切换的关键是能够通过xpath获取界面上的所有元素,选择每个界面上的元素。所以我们需要用到一个第三方包JsoupXpath以及一系列相关的关联包,需要的同学可以百度下载,或加我的微信423462664领取。
有了包,我们还需要理解iframe在selenium到底是什么样的。我们可以通过driver.getPageSource();方法获取selenium能够看到的网页代码,当我们对着有iframe的页面拉取时,我们会发现,iframe里的东西都是空的!!

当切换了iframe之后,在调用driver.getPageSource();方法,界面的代码就变成了:

我们看到上面的代码iframe的标签不见了,取而代之的是整个页面只出现iframe底下的代码,除了#document标记,请看下图,下图是在chrome里看到的iframe底下代码。

思考,如何自动切换iframe

所以我们想利用文档一次性拿下包括iframe的源码是不可能的,本人一开始想到的解决方案是通过driver.getPageSource();拿到所有包括iframe底下源码,再找到需要点击的元素,再逐级向上级寻找,生成相对应xpath,通过传入xpath和driver对象进行操作,因为不能够知道主 html下的iframe里的代码,也不知道iframe下的iframe有无更多的iframe,要解决这里就必须使用递归,去寻找各个iframe里是否有匹配的代码,而JsoupXpath里提供了所需要的全部接口。下面是代码:


/**
* 在各个iframe中寻找元素
* 作者:李星明
* 2018-10-17
* @author Xingming.Li
* @param driver webdriver对象,注意传递过来时,清除至默认框架,意思是调用
* @param xpath 需要寻找元素的xpath,该方法仅支持使用xpath时的搜索
* @return 返回
*/

public static WebElement findIframeElement(WebDriver driver ,String xpath)
{
String pageSource = driver.getPageSource();
WebElement element = null;
try{
element = driver.findElement(By.xpath(xpath));
}catch(Exception e)
{
e.printStackTrace();
}
if(null!= element)
{
return element;
}

boolean ifHasIframe = jsoupUtil.ifHasIframe(pageSource);
if(ifHasIframe == true)
{
int i = 0;
while(true)
{
try{
driver.switchTo().frame(i);

element = findIframeElement(driver,xpath);
if(null!= element)
{
return element;
}
//返回父框架寻找下一个
driver.switchTo().parentFrame();
}catch(Exception e)
{
e.printStackTrace();
break;
}
i++;
}
}else
{

}
return null;
}
public static boolean ifHasIframe(String pageSource)
{
String xpath="//iframe";
JXDocument jxDocument = new JXDocument(pageSource);
List<Object> rs = jxDocument.sel(xpath);
for (Object o:rs){
if (o instanceof Element){
// int index = ((Element) o).siblingIndex();
// System.out.println(index);
// Element element = (Element) o;
return true;
}
System.out.println(o.toString());
}
return false;
}

通过调用findIframeElement(WebDriver driver ,String xpath),能够有效找出html与所有iframe底下匹配的xpath(注意,匹配的xpath必须是唯一)

调用findIframeElement注意事项

在实际调用中,可能很多同学已经切换了多个iframe,findIframeElement这个方法是在出现了异常之后,进行调用的,调用之前之后都需要做一定的处理,下面是我在点击行为时,调用的代码

                                                        //打印异常
e.printStackTrace();
driver.switchTo().defaultContent();
element = jsoupUtil.findIframeElement(driver, rePath);
if(null!= element)
{

System.out.println("查找成功");
try{
element.click();
}catch(Exception e2)
{

}
//如果下一个行为不需要切换框架即可点击,则不要先切回到最主要的框架里去。
// driver.switchTo().defaultContent();
}else
{
System.out.println("查找失败");
if (null != Parameter.getParameter("uploadExption")
&& Parameter.getParameter("uploadExption")
.equals("1"))
{
new exceptionAction().reportExption(...);
}
return failed(...);
}
}

不同iframe下相同的xpath控件识别

我们在实际的项目使用中很快就遇到了在chrome浏览器复制xpath,但是在搜索中能够匹配两次xpath的控件,必须要通过修改xpath使得该控件唯一,才能使得脚本能够正常运行。(下面提供一个实际案例)

如红圈所示,提交与发送按钮在chrome浏览器复制xpath时居然是一样的!

必须修改成唯一方能放至程序执行。譬如改成如下的:
//*[@id="btnSubmit"][@value="提 交"]

最后感悟

我们遇到问题,首先是要想到能够解决,然后再是有能力去解决,但我却还没看到有人能够贡献出来代码真正解决这些问题,希望各位大神多多加油多多共享自己 的代码。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 8 条回复 时间 点赞

这思路,佩服……无话可说

最后的感悟和iframe切换有啥关系吗?

没明白重点在哪

arrow 回复

这篇文章对于存在大量iframe的操作的同学,非常有用

恒温 回复

😂 当然有关系,我没有提我用了docker啊,还是微服务什么的框架,我只讲如何自动切换框架识别到需要识别的元素

iframe 页面有的要滑动才加载的,getPageSource不行的吧

hello 回复

这位兄弟提的问题相当好!那只能先滑动,再点击了,理论上对框架代码不用什么修改,写脚本的同事要注意!

最后的感悟和iframe切换有啥关系吗?

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up