选择器的功能:选中⻚⾯中指定的标签元素选择器的种类分为基础选择器和复合选择器,常⻅的元素定位⽅式可以通过id选择器和⼦类选择器来进⾏定位。
打开开发者工具
鼠标右键 copy selector
ctrl+f打开查找框,复制到查找框看是否是唯一定位
无法唯一确定时,需要时要自己修改选择器
XML路径语⾔,不仅可以在XML⽂件中查找信息,还可以在HTML中选取节点。xpath使⽤路径表达式来选择xml⽂档中的节点。
//*
//[指定节点]
//ul :获取HTML⻚⾯所有的ul节点
//input:获取HTML⻚⾯所有的input节点
/
//span/input
..
//input/.. 获取input节点的⽗节点
[@...]
//*[@id='kw'] 匹配HTML⻚⾯中id属性为kw的节点
注意:xpath的索引是从1开始的。
百度首页通过://div/ul/li[3] 定位到第三个百度热搜标签
更便捷的⽣成selector/xpath的⽅式:右键选择复制"Copy selector/xpath"
注意:元素的定位⽅法必须唯⼀。建议选择selector。
问题:既然可以⼿动复制 selector/xpath的⽅式 ,为什么还有了解语法?
手动复制的selector/xpath表达式并不⼀定满⾜上⾯的唯一性的要求,有时候也需要⼿动的进行修改表达式,如:想要匹配到百度⾸⻚指定的新闻⽂本或者节点集,直接使⽤ #hotsearch-contentwrapper > li 不能满足
报错原因:浏览器版本太低与驱动管理器版本不匹配
更新后成功
注意:登录状态下和非登录状态下打开的页面不一定相同,在做自动化测试时一定要注意页面状态的一致性
findElement(By);
findElements(By);
public interface WebElement extends SearchContext, TakesScreenshot {
void click();//点击
void submit();//提交
void sendKeys(CharSequence... keysToSend);//模拟键输入
void clear();//清空
String getTagName();
default String getDomProperty(String name) {
throw new UnsupportedOperationException("getDomProperty");
}
default String getDomAttribute(String name) {
throw new UnsupportedOperationException("getDomAttribute");
}
String getAttribute(String name);//获取属性值
default String getAriaRole() {
throw new UnsupportedOperationException("getAriaRole");
}
default String getAccessibleName() {
throw new UnsupportedOperationException("getAccessibleName");
}
boolean isSelected();
boolean isEnabled();
String getText();//获取文本信息
List<WebElement> findElements(By by);
WebElement findElement(By by);
default SearchContext getShadowRoot() {
throw new UnsupportedOperationException("getShadowRoot");
}
boolean isDisplayed();
Point getLocation();
Dimension getSize();
Rectangle getRect();
String getCssValue(String propertyName);
}
//找到百度⼀下按钮并点击
driver.findElement(By.cssSelector("#su")).click();//页面绝大多数区域都可以点击,不只是按钮,页面影藏的标签、不可见的标签不能点击
driver.findElement(By.cssSelector("#kw")).sendKeys("输⼊⽂字");
driver.findElement(By.cssSelector("#kw")).sendKeys("我爱游戏");
driver.findElement(By.cssSelector("#kw")).clear();
driver.findElement(By.cssSelector("#kw")).sendKeys("我爱学习");
String bdtext = driver.findElement(By.xpath("//*[@id="title-content"]/span[1]")).getText();
System.out.println("打印的内容是:"+bdtext);
注意区分文本和属性值
问题:是否可以通过 getText() 获取到“百度⼀下按钮”上的⽂字“百度⼀下”呢?
注意:⽂本和属性值不要混淆了。获取属性值需要使⽤⽅法 getAttribute("属性名称") ;
driver.getWindowHandle(); //返回值String
driver.getWindowHandles();//返回值Set<Sreing>
String curWindow = driver.getWindowHandle();
Set<String> allWindow = driver.getWindowHandles();
for( String w : allWindow){
if(w!=curWindow){
driver.switchTo().window(w);
}
}
//窗⼝最⼤化
driver.manage().window().maximize();
//窗⼝最⼩化
driver.manage().window().minimize();
//全屏窗⼝
driver.manage().window().fullscreen();
//⼿动设置窗⼝⼤⼩
driver.manage().window().setSize(new Dimension(1024, 768));
//获取所有句柄
//获取当前停留⻚⾯句柄
String curWindow = driver.getWindowHandle();
Set<String> allWindow = driver.getWindowHandles();
for( String w : allWindow){
if(w!=curWindow){
driver.switchTo().window(w);
}
}
自动化一般不会存在打开好多个标签页 不要为难自己
我们的⾃动化脚本⼀般部署在机器上⾃动的去运⾏,如果出现了报错,我们是不知道的,可以通过抓拍来记录当时的错误场景
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
//屏幕截图
void getScreenShot(String str) throws IOException {
// /src/test/image/
// /2024-08-23/
// /test01-13470.png
// /test02-13470.png
// /2024-0-24/
// /test01-12470.png
// /test01-12470.png
//屏幕截图
SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sim2 = new SimpleDateFormat("HHmmss");
String dirTime = sim1.format(System.currentTimeMillis());
String fileTime = sim2.format(System.currentTimeMillis());
// .src/test/image/2024-08-24/test01-13470.png
String filename ="./src/test/image/"+ dirTime + "/"+str + "-" + fileTime + ".png";
System.out.println(filename);
File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
//scrFile放到指定位置
FileUtils.copyFile(srcFile, new File(filename));
}
+ 屏幕截图⽅法需要额外导⼊包:
~~~java
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file,new File(filename));
driver.close();//关闭当前标签页
注意:窗⼝关闭后driver要重新定义
driver.quit(); //关闭浏览器、释放driver对象
假如写自动化代码出现了NoSuchElement错误
第一步:在报错的代码前添加Thread. sleep(秒),设置的时间长一点
第二步:执行自动化,在自动化打开的页面里打开前端开发者工具,手动检查元素是否真的不存在
通常代码执⾏的速度⽐⻚⾯渲染的速度要快,如果避免因为渲染过慢出现的⾃动化误报的问题呢?可以使⽤selenium中提供的三种等待⽅法:
隐式等待是⼀种智能等待,他可以规定在查找元素时,在指定时间内不断查找元素。如果找到则代码继续执⾏,直到超时没找到元素才会报错。
//隐式等待1000毫秒
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(1000));
//隐式等待5秒
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
显⽰等待也是⼀种智能等待,在指定超时时间范围内只要满⾜操作的条件就会继续执⾏后续代码
new WebDriverWait(driver, Duration.ofSeconds(3)).until($express)
ExpectedConditions预定义方法的一些示例:
elementToBeClickable(By locator) ‒ _⽤于检查元素的期望是可见的并已启用,以便您可以单击它。
textToBe(Bylocator,String str) - 检查元素。精确匹配
presenceOfElementLocated(Bylocator) ‒ 检查⻚⾯的 DOM 上是否存在元素。
urlToBe(java.lang.String url) ‒ 检查当前⻚⾯的 URL 是⼀个特定的 URL。
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));
2 boolean ispass = wait.until(ExpectedConditions.textToBe(By.cssSelector("#s-topleft > a:nth-child(1)"), "新闻"));
if(ispass){
System.out.println("测试通过");
}else {
System.out.println("测试失败");
}
优点:显⽰等待是智能等待,可以⾃定义显⽰等待的条件,操作灵活
缺点:写法复杂、只做用在当前条件上
问题:显示等待和隐式等待一起使用会怎么样?
可能会导致不可预测的等待时间,谨慎使用
driver.navigate().back();
driver.navigate().forward();
driver.navigate().refresh();
// 更⻓的⽅法
driver.navigate().to("https://selenium.dev");
// 简洁的⽅法
driver.get("https://selenium.dev");
案例:百度首页测试https://tool.lu/标签⼊⼝
弹窗是在⻚⾯是找不到任何元素的,这种情况怎么处理?
使⽤selenium提供的Alert接⼝
//切换弹窗
Alert alert = driver.switchTo.alert();
//确认
alert.accept()
//取消
alert.dismiss()
Alert alert = driver.switchTo.alert();
alert.sendKeys("hello");
alert.accept();
alert.dismiss();
点击文件上传的场景下会弹窗系统窗⼝,进⾏⽂件的选择。selenium⽆法识别⾮web的控件,上传⽂件窗⼝为系统自带,⽆法识别窗⼝元素但是可以使⽤sendkeys来上传指定路径的⽂件,达到的效果是⼀样的
WebElement ele = driver.findElement(By.cssSelector("body > div > div >
input[type=file]"));
ele.sendKeys("D:\selenium2html\selenium2html\upload.html");
设置⽆头模式
设置浏览器加载策略