Java爬虫之selenium(超详细)

一、selenium引入和功能

使用maven导入依赖

<!-- 添加 Selenium WebDriver 依赖 -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.10.0</version>
</dependency>

<!-- 如果需要使用特定的浏览器引擎,还需添加对应的驱动依赖 -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-chrome-driver</artifactId>
    <version>4.9.0</version>
</dependency>

支持的浏览器

selenium的功能

(1)主要被用于自动化测试

(2)爬虫和数据抓取

(3)网站监控:定期检查网站是否在线,以及页面元素是否按预期显示,可以用来监控网站的健康状态

(4)视觉测试:结合图像识别技术,检查网页的视觉元素是否符合设计

(5)浏览器兼容性测试

(6)性能测试:模拟用户行为来评估网站的性能

(7)api测试

(8)用户旅程映射

(9)自动化报告生成

二、chromeDriver的安装

如何查看本机的chrome版本?

打开chrome浏览器,地址输入"chrome://version/",可以看到版本为:124.0.6367.61

匹配对应的chromedriver并下载

Selenium 3.0及以上版本中,Firefox浏览器驱动独立了,需要下载和设置浏览器驱动。

对于Chrome,也需要下载对应的ChromeDriver

记住放置的路径,我这里是:D:\Drivers\chromedriver-win64

在服务器上例如Centos如何安装Chrome

安装chrome:

curl https://intoli.com/install-google-chrome.sh | bash 

查看chrome版本:

google-chrome --version

下载chromedriver同上

三、selenium举例

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class GoogleSearchTest {

    private WebDriver driver;

    @BeforeMethod
    public void setUp() {
        // 设置WebDriver路径
        System.setProperty("webdriver.chrome.driver", "D:\\Drivers\\chromedriver-win64");
        // 初始化WebDriver
        driver = new ChromeDriver();
    }

    @Test
    public void testGoogleSearch() {
        // 打开Google首页
        driver.get("https://www.google.com");
        // 等待页面加载完成
        driver.manage().timeouts().implicitlyWait(10, java.util.concurrent.TimeUnit.SECONDS);
        // 寻找搜索框元素并输入搜索词
        driver.findElement(By.name("q")).sendKeys("Selenium");
        // 点击搜索按钮
        driver.findElement(By.name("btnK")).click();
        // 验证页面标题是否包含搜索词
        assert driver.getTitle().contains("Selenium");
    }

    @AfterMethod
    public void tearDown() {
        // 关闭浏览器
        driver.quit();
    }
}

四、selenium内容详解

(一)chrome启动参数

public static void main(String[] args) {
    // 设置系统属性,指定chromeDriver的路径
    System.setProperty("webdriver.chrome.driver","D:\\Drivers\\chromedriver-win64");
    // 创建chromeOptions对象,可以设置Chrome的启动参数
    ChromeOptions options = new ChromeOptions();
    
    options.addArguments("--disable-extensions");  // 禁用浏览器扩展。
    options.addArguments("--headless");  // 启用无头模式(不显示浏览器界面)
    options.addArguments("window-size=1920x3000");    // 指定浏览器分辨率
    options.addArguments("start-maximized");    // 启动时最大化浏览器窗口
    options.addArguments("--disable-gpu");    // 禁用GPU硬件加速。
    options.addArguments("--user-data-dir");    // 指定用户数据目录,用于自定义Chrome的用户配置文件
    options.addArguments("--disable-popup-blocking");    // 禁用弹出窗口拦截器。
    options.addArguments("--no-sandbox");    // 彻底停用沙箱,这在非桌面环境中运行Chrome时非常有用
    options.addArguments("--disable-web-security");    // 禁用网页安全性功能,用于解决跨域问题
    options.addArguments("--ignore-certificate-errors");    // 忽略SSL证书错误
    options.addArguments("--incognito");    // 以隐身模式启动浏览器
    options.addArguments("--proxy-server");    // 设置代理服务器地址和端口,例如 --proxy-server=127.0.0.1:8087
    options.addArguments("--window-position");    // 设置浏览器窗口的位置
    options.addArguments("--window-size");    // 设置浏览器窗口的大小
    options.addArguments("--disable-javascript");    // 禁用JavaScript
    options.addArguments("--disable-plugins");    // 禁用插件
    options.addArguments("--disable-images");    // 禁用图像
}

(二)元素定位方式

不管哪种方式都应该保证定位要操作的对象是唯一的

  • 1、使用元素的ID属性来定位元素,这是最快且最准确的方式

优先使用ID定位;

ID是元素在HTML中的唯一标识符,使用ID进行定位是最直接、最快速的方式。如果元素有唯一的ID,应该优先使用ID进行定位,因为它的效率最高

driver.findElement(By.id("id值"));
  • 2、使用CSS选择器来定位元素

使用CSS选择器

Selenium官方推荐使用CSS选择器进行元素定位,因为CSS选择器的效率通常高于XPath,并且语法更加简洁。

CSS的获取可以用chrome的F12开发者模式中Element-右键-copy-copy selector来获取

driver.findElement(By.cssSelector("input[type='submit']"));

// 定位多个元素,返回一个元素列表
List<WebElement> elements = driver.findElements(By.cssSelector("input"));
  • 3、使用元素的class属性来定位元素
driver.findElement(By.className("elementClass"));
  • 4、通过元素的标签名来定位元素
driver.findElement(By.tagName("input"));
  • 5、通过元素的name属性来定位元素
driver.findElement(By.name("elementName"));
  • 6、通过链接的完整文本内容来定位<a>标签元素
driver.findElement(By.linkText("Link Text"));
  • 7、通过链接文本的部分内容来定位<a>标签元素
driver.findElement(By.partialLinkText("Partial Link Text"));
  • 8、通过包含指定文本的class属性来定位元素
driver.findElement(By.classNameContaining("partialClassName"));
  • 9、通过包含指定文本的标签名来定位元素
driver.findElement(By.tagNameContaining("partialTagName"));
  • 10、通过包含指定文本的CSS选择器来定位元素
driver.findElement(By.cssSelectorContaining("partialCssSelector"));
  • 11、通过包含指定文本的XPath表达式来定位元素
driver.findElement(By.xpathContaining("//input[contains(@class,'partialClass')]"));
  • 12、使用XPath表达式来定位多个元素,返回一个元素列表
List<WebElement> elements = driver.findElements(By.xpath("//input"));
  • 13、使用XPath表达式来定位元素,XPath是一种在XML文档中查找信息的语言,也适用于HTML

避免使用xpath的绝对路径

绝对路径对页面结构要求比较严格,不建议使用绝对路径,因为页面结构的微小变化都可能导致定位失败 

XPATH的获取可以用chrome的F12开发者模式中Element-右键-copy-copy xpath来获取

driver.findElement(By.xpath("//input[@type='submit']"));

  • 其他

1、使用逻辑运算符组合定位:使用XPath的逻辑运算符and、or来组合更多元素特征,以提高定位的准确性。

2、避免使用过于通用的选择器:如find_element_by_tag_name,因为这种方法可能会返回多个元素,需要进一步使用下标来定位特定的元素

3、考虑元素的可访问性:选择那些在DOM结构中相对稳定且不太可能变化的元素属性进行定位

4、动态元素的处理:对于动态生成的元素,可以考虑使用显式等待(Explicit Wait),等待元素可见或可操作后再进行定位

5、框架和iframe的处理:当元素位于iframe或不同的框架中时,需要先切换到相应的框架中再进行元素定位。

6、异常处理:在定位元素时,应该添加异常处理逻辑,以便在元素未找到时能够给出清晰的错误信息。

(三)设计模式 Page Object Model (POM)

将页面分解成独立的对象,每个对象代表一个页面或页面的一部分,有助于组织测试代码和提高可维护性

  • POM概念

页面对象模型是一种设计模式,它提倡将UI元素抽象成对象,并围绕这些对象组织测试代码。这一模式不仅提升了测试脚本的可读性和可维护性,还促进了代码的重用

  • POM优势
  • 分离关注点:将测试逻辑与页面元素分离,使测试脚本更加清晰。
  • 易于维护:页面变化时,只需修改对应的页面对象类,无需改动所有测试案例。
  • 代码复用:页面对象可以在多个测试案例中重复使用,减少冗余代码。
  • 提高可读性:通过将操作封装成方法,使得测试代码更加易于理解。
  • 提高可维护性:减少测试脚本对页面结构变化的敏感度,提高测试代码的可维护性
  • POM的设计原则
  • 抽象每一个页面:为每个页面创建一个对应的页面对象类。
  • 页面中元素不暴露:仅暴露操作元素的方法,隐藏元素的具体定位细节。
  • 页面不应该有繁琐的继承关系:避免页面对象之间的复杂继承结构。
  • 页面中不是所有元素都需要涉及到:只对核心业务元素进行建模。
  • 把页面划分功能模块:在Page中实现这些功能方法
  • POM的实现
  • 创建页面类:为每个页面创建一个类,该类包含页面的所有元素定位器和操作方法。
  • 封装元素操作:在页面类中封装对元素的所有操作,如点击、输入文本等。
  • 使用Page Factory:Selenium提供了Page Factory模式,可以进一步简化页面对象的创建和管理

(四)等待机制 及 异常处理

三种等待

  • 硬等待【Hard Wait】(也叫强制等待)
Thread.sleep(3000);  // 硬等待,等待3秒
  • 隐式等待【Implicit Wait】:等待页面所有元素
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlywait(10,TimeUint.SECONDS); // 设置隐式等待时间为10秒
  • 显式等待【Explicit Wait】:可以指定等待页面的某一个元素

显式等待使用WebDriverWait和ExpectedConditions来等待特定的条件发生

WebDriverWait接收两个参数:一个WebDriver对象和一个秒数(最大等待时间)。如果在指定的时间内条件没有满足,将会抛出一个TimeoutException异常

WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
// 显式等待,等待一个元素可见,最多等待10秒
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("xxxid值")));

ExpectedConditions的常用示例(注意java和python的方法命名不相同,不能直接套用

(1)等待元素可见:会等待直到ID为kw的元素在DOM中可见

WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("kw")));

(2)等待元素可点击:

WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("elementId")));

(3)等待元素存在

WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("elementId")));

(4)等待页面标题:会等待直到页面的标题完全匹配“预期的标题”

wait.until(ExpectedConditions.titleIs("预期的标题"));

区别

【硬等待】

如果等待时间是三天,那么强制等待会一直等待直到三天结束;

通常不推荐使用,因为它会无条件的阻塞进程,效率低;

【隐式等待】

是等待页面所有的元素加载完成后才执行下面代码,如果加载过程中超过等待时间就会报错

【显示等待】

显示等待最长等待时间为设置的时间,在期间如果满足等待结束条件(until()方法中)就会结束等待

【总结】

隐式等待和显示显式等待是常用的等待方式,只能等待可以根据项目需求自定义实现

等待超时异常处理

WebDriverWait等待超时了

  • 1、增加等待时间 - 针对页面加载缓慢网络延迟引起的异常
  • 2、优化元素定位 - 确保使用的XPath或CSS选择器准确且唯一,避免因定位不当导致的超时
  • 3、使用Try-Catch块来捕获和处理TimeoutException,可以防止脚本因超时而突然失败,并允许执行其他操作或记录错误
  • 4、增加重试机制
for (int i = 0; i < maxAttempts; i++) {
    try {
        element = WebDriverWait(driver, 5).until(ExpectedConditions.presence_of_element_located((By.ID, "elementID")));
        // 执行元素上的操作
        break; // 如果成功,退出循环
    } catch (TimeoutException e) {
        if (i < maxAttempts - 1) {
            // 如果还有尝试次数,继续重试
            continue; 
        } 
        else {
            // 如果已达最大尝试次数,抛出异常
            throw e; 
        }
    }
}
  • 5、检查网络连接 - 确保测试环境的网络连接稳定,因为不稳定的网络连接可能会导致WebDriver与网站交互时超时
  • 6、更新Selenium和WebDriver - 保持Selenium和对应的WebDriver更新到最新版本,以确保与浏览器的兼容性 

(五)浏览器及窗口操作

包含浏览器的:前进、后退、滚动条操作、最大化、全屏、宽高设置、获取窗口位置和大小、设置窗口位置和大小

WebDriver webDriver = new ChromeDriver();
        
webDriver.get("https://www.baidu.com");  //打开百度首页
       
webDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴"); //搜索迪丽热巴
webDriver.findElement(By.cssSelector("#su")).click();
        
sleep(3000);//强制等待3秒
      
webDriver.navigate().back();           //浏览器后退

webDriver.navigate().refresh();        //刷新


webDriver.navigate().forward();        //浏览器前进
//浏览器滚动条操作,此时需要将webDriver强制转换
//executeScript()中是js代码,scrollTop方法是向上滚动多少个像素
((JavascriptExecutor)webDriver).executeScript("document.documentElement.scrollTop=10000");


webDriver.manage().window().maximize();        //浏览器最大化

webDriver.manage().window().fullscreen();        //浏览器全屏
webDriver.manage().window().setSize(new Dimension(600,1000));        //设置浏览器宽高
Dimension size = webDriver.manage().window().getSize();  // 获取窗口大小:size.getWidth() 、size.getHeight()
webDriver.manage().window().setSize(new Dimension(800, 600));   // 设置窗口大小



Point position = webDriver.manage().window().getPosition();  // 获取窗口位置:position.getX()、position.getY()
webDriver.manage().window().setPosition(new Point(100, 100));  // 设置窗口位置

(六)截图操作

需要导入依赖包,如Commons IO,进行截图操作

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

//浏览器截图
    private static void test11() throws InterruptedException, IOException {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com/");
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("软件测试");
        webDriver.findElement(By.cssSelector("#su")).click();
        sleep(3000);
        //强制转换进行截图以文件形式存储
        File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(file,new File("d://测试.png"));

    }

 (七)键盘和鼠标操作

利用Actions和Keys类来模拟键盘操作,包括文本输入、按键和组合键序列

增强自动化脚本的用户交互能力

键盘事件

通过sendKeys()调用

单个使用:

1.sendKeys(Keys.TAB) # TAB

2.sendKeys(Keys.ENTER) # 回车

3.sendKeys(Keys.SPACE) #空格键

4.sendKeys(Keys.ESCAPE) #回退键(Esc)

组合使用:

1.sendKeys(Keys.CONTROL,‘a’) #全选(Ctrl+A)

2.sendKeys(Keys.CONTROL,‘c’) #复制(Ctrl+C)

3.sendKeys(Keys.CONTROL,‘x’) #剪贴(Ctrl+X)

4.sendKeys(Keys.CONTROL,‘v’) #粘贴(Ctrl+V)

 private static void test() throws InterruptedException {
        ChromeOptions options = new ChromeOptions();
        //允许所有请求
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        //  打开百度网页
        webDriver.get("https://www.baidu.com");
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
        //control+a
        webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"A");
        sleep(3000);
        //control+x
        webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"X");
        sleep(3000);
        //control+v
        webDriver.findElement(By.cssSelector("#kw")).sendKeys(Keys.CONTROL,"V");
        

    }

鼠标事件

通过ActionChains 类实现鼠标执行的操作:

1、contextClick() 右击

2、doubleClick() 双击

3、dragAndDrop() 拖动

4、moveToElement() 移动

5、不能发送鼠标滚轮操作

//鼠标事件
    private static void test() throws InterruptedException {
        ChromeOptions options = new ChromeOptions();
        //允许所有请求
        options.addArguments("--remote-allow-origins=*");
        WebDriver webDriver = new ChromeDriver(options);
        //  打开百度网页
        webDriver.get("https://www.baidu.com");
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
        webDriver.findElement(By.cssSelector("#su")).click();
        sleep(3000);
        //找到图片按钮
        WebElement webElement = webDriver.findElement(By.cssSelector("#\\32  > div > div > div > div > div.list-scroll_7E1go > div > div:nth-child(1) > div.avatar-wrapper_622F1 > a:nth-child(1) > div > div._capsule_1e0bo_35.capsule_GwMlS.cu-line-clamp-1"));
        //鼠标右击操作s
        Actions actions = new Actions(webDriver);
        //鼠标移动到图片,右击,执行
        sleep(3000);
        actions.moveToElement(webElement).contextClick().perform();
    }

(八)勾选复选框

  • 选中一组type为checkbox的数据
private static void page01() {
        // 创建一个浏览器驱动
        WebDriver webDriver = new ChromeDriver();
        // 打开网页
        webDriver.get("http://localhost:63342/Test/src/main/page/teste01.html?_ijt=bbsd02k86b9564t8p03vfmeff1&_ij_reload=RELOAD_ON_SAVE");
        // 获取到所有的input标签对应的元素
        List<WebElement> webElements = webDriver.findElements(By.cssSelector("input"));
        // 判断每一个input标签里面type值是checkbox进行点击,否则不点击
        for(int i = 0; i < webElements.size(); i++) {
            if(webElements.get(i).getAttribute("type").equals("checkbox")) {
                webElements.get(i).click();
            } 
        }
    }

(九)多层框架/窗口定位

对于一个web 应用,经常会出现框架(iframe) 或窗口(window)的应用,这样如果我们定位元素就不能直接右击copy他的xpath或者是cssselector来定位;但是可以通过switchTo()方法定位到frame下或者window下,然后通过元素css选择器或者xpath定位

 private static void page02() {
        // 创建浏览器驱动
        WebDriver webDriver = new ChromeDriver();
        // 打开网页
        webDriver.get("http://localhost:63342/Test/src/main/page/test02.html?_ijt=ukda3p0a62ntrthar4gi039p32&_ij_reload=RELOAD_ON_SAVE");
        // 需要先定位到frame下再定位到click
        webDriver.switchTo().frame("f1");
        webDriver.findElement(By.cssSelector("body > div > div > a")).click();
        // 目标元素不在iframe,可以直接获取
//        String h3_text = webDriver.findElement(By.cssSelector("body > div > div > h3")).getText();
//        System.out.println(h3_text);
    }

(十)操作下拉框

下拉框里的内容需要进行两次定位,先定位到下拉框对下拉框进行操作后,再定位到下拉框内里的选项

 private static void page03() {
        // 创建浏览器驱动
        WebDriver webDriver = new ChromeDriver();
        // 打开网页
        webDriver.get("http://url地址");
        // 操作下拉框
        Select select = new Select(webDriver.findElement(By.cssSelector("#ShippingMethod")));
//        select.selectByValue("12.51");
        select.selectByIndex(2);
    }

(十一)上传文件操作

在selenium webdriver 只要定位上传按钮,通过sendKeys 添加本地文件路径就可以了。

绝对路径和相对路径都可以,关键是上传的文件存在

 private static void page05() {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("http://url地址");
        // 找到按钮(上传文件的按钮),输入一个字符串
        webDriver.findElement(By.cssSelector("input")).sendKeys("C:\Users\34085\Desktop\hello.txt");
    }

(十二)处理动态元素

使用显式等待 和 隐式等待来处理动态元素
  • 1、使用WebDriverWait和Expected Conditions
动态元素往往是在页面加载完成后通过JavaScript动态生成的。使用 WebDriverWait 结合 Expected Conditions 可以等待元素在页面上可见或可点击后再进行操作
WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("dynamicElement")));
  • 2、根据部分属性值定位
如果元素的ID或class是动态生成的,可以使用XPath中的contains()、starts-with()和ends-with()函数来根据部分属性值定位元素
// 这样可以匹配ID中包含"auto-id"的元素,即使ID是动态生成的 driver.findElement(By.xpath("//div[contains(@id, 'auto-id')]"));
  • 3、根据相对关系定位
如果动态元素与其附近的父节点、子节点或兄弟节点有固定的相对关系,可以根据这些固定元素来定位动态元素
  • 4、根据DOM顺序index定位
找到元素在DOM中的顺序索引,然后根据索引进行定位。这种方法可能不够稳定,如果可以,还是推荐使用其他方法
  • 5、使用CSS选择器
CSS选择器提供了一种灵活的方式来定位元素,尤其是当元素的ID或class是动态生成时。例如,可以使用CSS属性选择器来定位元素
driver.findElement(By.cssSelector("input[type='text']"));
  • 6、结合使用多种定位方法
在某些情况下,可以结合使用多种定位方法来提高定位的准确性和成功率。例如,可以先通过CSS选择器定位到一个父元素,然后再通过相对路径定位到其子元素
  • 7、优化等待时间
动态元素的加载可能需要时间,因此合理设置等待时间是提高脚本稳定性的关键。避免使用硬编码的等待时间(如 Thread.sleep ),而是使用 WebDriverWait 来动态等待元素加载完成

(十三)处理弹窗

使用Alert类来处理弹窗:

1.text 返回alert 中的文字信息。

2.accept 点击确认按钮。

3.dismiss 点击取消按钮,如果有的话。

4.sendKeys 输入值,如果alert 没有对话框就不能用了,不然会报错。

private static void page04() throws InterruptedException {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("http://url地址");
        webDriver.findElement(By.cssSelector("button")).click();
        // alert弹窗确定
//        webDriver.switchTo().alert().accept();
        // alert弹窗取消
//        webDriver.switchTo().alert().dismiss();
        webDriver.switchTo().alert().sendKeys("你好");
        webDriver.switchTo().alert().accept();
    }

(十四)切换窗口

获取当前窗口句柄并切换到新窗口

// 进入百度页面然后点击新闻进入新闻页面,此时如果我们需要在新闻页面输入相关内容,是不能直接通过选择器定位实现的
// 我们需要先实现页面切换才能在新闻页面搜索内容
//浏览器切换窗口
    private static void test10() throws InterruptedException {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.baidu.com/");
        //点击新闻页面,在新闻面输入相关信息
        webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
        //getWindowHandles获得所有窗口句柄
        //getWindowHandle获取get打开的窗口句柄
        // 获取到浏览器所有的窗口句柄
        Set<String> handles = webDriver.getWindowHandles();
        //遍历所有的窗口句柄
        String target_handle = "";
        for(String handle:handles) {
            //赋值
            target_handle = handle;
        }
        //System.out.println(target_handle);
        //在新闻页面搜索新闻联播
        webDriver.switchTo().window(target_handle);
        sleep(3000);
        webDriver.findElement(By.cssSelector("#ww")).sendKeys("新闻联播");
        webDriver.findElement(By.cssSelector("#s_btn_wr")).click();
       
    }

(十五)拖拽操作

使用Actions类进行复杂的鼠标操作,如拖拽

from selenium.webdriver.common.action_chains import ActionChains
private static void test() {
        WebDriver webDriver = new ChromeDriver();
        webDriver.get("https://www.URL地址/");
        element_to_drag = driver.find_element_by_id("source");
        target_element = driver.find_element_by_id("target");
        // 方法一:直接将源元素拖拽到目标元素上
        actionsA = ActionChains(driver);
        actionsA.drag_and_drop(element_to_drag, target_element).perform();
        // 方法二:模拟了更细致的拖拽过程,包括按住源元素(click_and_hold)、移动到目标元素位置(move_to_element)、然后释放(release)
        actionsB = ActionChains(driver)
        actionsB.click_and_hold(element_to_drag).move_to_element(target_element).release().perform()
    }

(十六)浏览器关闭

可以通过quit()和close()方法关闭浏览器

quit关闭整个浏览器并且清空缓存,close关闭当前页面

 //浏览器关闭操作
    private static void test09() throws InterruptedException {
        WebDriver webDriver = new ChromeDriver();
        //打开百度首页
        webDriver.get("https://www.baidu.com");
        //搜索迪丽热巴
        webDriver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
        webDriver.findElement(By.cssSelector("#su")).click();
        //强制等待3秒
        sleep(3000);
        webDriver.close(); // close关闭当前页面
        webDriver.quit();  // quit关闭整个浏览器并且清空缓存

    }

六、如何处理浏览器驱动更新导致的问题

(1)确保webdriver与浏览器版本匹配

(2)手动下载WebDriver并使用Selenium的Service类来加载。这样可以控制WebDriver的版本,避免自动更新带来的问题

(3)在代码中添加异常处理逻辑,捕获TimeoutException并提供相应的错误信息和日志,以便进行问题定位和调试

(4)定期更新selenium和webdriver

(5)避免浏览器自动更新

(6)在测试开始之前,确保浏览器是干净的,没有被其他扩展或插件干扰。如果浏览器崩溃或被关闭,可以考虑重启浏览器并重新运行测试

七、selenium如何用于网站监控

(一)监听网页内容变化

通过定期检查网页上特定元素的内容,可以监控网页内容的变化。例如,可以监控商品价格、库存状态或新闻更新等

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
// 这段代码会在指定的网页上查找价格元素,并检测其内容的变化。如果价格发生变化,它会输出新的价格。
// 我们可以结合邮件报警+定时任务,当价格有变动时,可以发送邮件
public class PriceWatcher {
    public static void main(String[] args) throws InterruptedException {
        System.setProperty("webdriver.chrome.driver", "chromedriver的地址");
        WebDriver driver = new ChromeDriver();
        driver.get("http://url地址");
        String previousPrice = "";
        while (true) {
            WebElement priceElement = driver.findElement(By.id("price")); // 假设价格的ID是"price"
            String currentPrice = priceElement.getText();
            if (!currentPrice.equals(previousPrice)) {
                System.out.println("价格变动: " + currentPrice);
                previousPrice = currentPrice;
            }
            Thread.sleep(5000); // 每5秒检查一次
        }
    }
}

补充:如果是监控价格:(1)可以将每次检查的价格存储到CSV文件或数据库中,以便进行历史价格分析。这可以通过在上述代码中添加文件写入逻辑来实现;(2)发送通知,如集成邮件报警;(3)添加异常处理

(二)监控网络请求

Selenium可以结合BrowserMob Proxy或其他工具来监控网络请求。BrowserMob Proxy是一个开源的代理服务器,可以捕获HTTP请求和响应

import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.util.List;
// 这段代码通过BrowserMob Proxy捕获了浏览器的所有HTTP请求和响应,并打印了请求的URL和响应状态。
// 通过这些方法,Selenium不仅可以用于自动化测试,还可以用于网站监控,帮助开发者和测试人员及时发现和响应网站的变化。
public class MonitorHttpRequests {
    public static void main(String[] args) {
        // 启动BrowserMob Proxy
        BrowserMobProxy proxy = new BrowserMobProxyServer();
        proxy.start(0);
        // 获取代理的地址
        Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
        // 设置WebDriver的代理
        ChromeOptions options = new ChromeOptions();
        options.setProxy(seleniumProxy);
        WebDriver driver = new ChromeDriver(options);
        // 启动请求捕获
        proxy.newHar("myHar");
        // 导航到网页
        driver.get("http://url地址");
        // 获取请求数据
        List<HarEntry> entries = proxy.getHar().getLog().getEntries();
        for (HarEntry entry : entries) {
            System.out.println("请求网址: " + entry.getRequest().getUrl());
            System.out.println("响应状态: " + entry.getResponse().getStatus());
        }
        // 关闭WebDriver与Proxy
        driver.quit();
        proxy.stop();
    }
}

八、selenium在性能测试中如何应用

  • 配置性能日志记录
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class PerformanceTestSetup {
    public static void main(String[] args) {
        // 设置ChromeDriver路径
        System.setProperty("webdriver.chrome.driver", "chromedriver路径");
        // 创建ChromeOptions对象
        ChromeOptions options = new ChromeOptions();
        // 启用性能日志记录
        options.setCapability("perfLoggingPrefs", "{\"enableNetwork\": true, \"enablePage\": true}");
        // 将配置应用于WebDriver对象
        WebDriver driver = new ChromeDriver(options);
        // 打开网页
        driver.get("http://example.com");
        // 执行操作
        // 关闭浏览器
        driver.quit();
    }
}
  • 获取并分析性能日志
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class PerformanceLogging {
    public static void main(String[] args) {
        // 设置WebDriver路径
        System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
        // 设置Chrome选项
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--auto-open-devtools-for-tabs");
        // 创建WebDriver实例
        WebDriver driver = new ChromeDriver(options);
        // 获取DevTools实例。 注意:以下代码需要Selenium 4及以上版本
        org.openqa.selenium.devtools.DevTools devTools = ((ChromeDriver) driver).getDevTools();
        devTools.createSession();
        // 启动性能监控
        devTools.send(org.openqa.selenium.devtools.v93.performance.Performance.enable());
        // 访问目标页面
        driver.get("http://example.com");
        // 获取性能指标
        LogEntries entries = driver.manage().logs().get(org.openqa.selenium.logging.LogType.PERFORMANCE);
        for (LogEntry entry : entries) {
            System.out.println(entry.getMessage());
        }
        // 关闭驱动
        driver.quit();
    }
}
  • 常见的性能指标
  • 响应时间(Response Time):客户端发送请求到接收到服务器响应的时间
  • 吞吐量(Throughput):指系统在单位时间内能处理的事务或请求的数量。高吞吐量表明系统能够处理大量的请求
  • 并发用户数(Concurrent Users):指系统能同时支持的最大用户数量( 这个指标对于理解系统在高负载下的表现非常重要)
  • 事务处理速率(Transaction Rate):系统在单位时间内能完成的事务数量。事务可以是任何用户操作,如登录、查询、更新等
  • 资源利用率(Resource Utilization):系统资源(如CPU/内存/磁盘I/O/网络带宽)的使用情况。高资源利用率可能表明性能瓶颈
  • 错误率(Error Rate):指在一定时间内失败的事务或请求所占的比例。低错误率是系统稳定性的重要指标
  • 页面加载时间(Page Load Time):对于Web应用,指从用户点击链接或输入网址到页面完全加载完成所需的时间
  • 首次内容绘制(Time to First Contentful Paint, TTFCP):指页面开始加载到首次内容(如文本或图像)被渲染到屏幕上的时间
  • 最大内容绘制(Time to Largest Contentful Paint, LTCP):指页面开始加载到最大文本块或图像被渲染到屏幕上的时间
  • 交互时间(Time to Interactive, TTI):指页面加载到主要子资源加载完成,且页面能够快速响应用户输入的时间
  • 总页面加载时间(Total Page Load Time):从用户开始导航到页面完全加载完成的时间
  • 服务器响应时间(Server Response Time):服务器处理请求并返回响应所需的时间
  • 网络时间(Network Time):数据在网络中传输的时间,包括请求和响应的往返时间
  • 数据库响应时间(Database Response Time):数据库处理请求并返回结果所需的时间
  • 系统稳定性(System Stability):在长时间运行或高负载下,系统是否能够保持性能和不出现故障
  • 可扩展性(Scalability):系统在增加负载时,性能如何变化,以及是否能够通过增加资源来提高性能

九、java+selenium+TestNG

TestNG是一个测试框架,它支持各种测试场景,包括单元测试、集成测试、端到端测试等。以下是如何在Java中使用Selenium和TestNG进行自动化测试

1、添加依赖

<!-- Selenium -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.141.59</version>
</dependency>

<!-- TestNG -->
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.4.0</version>
    <scope>test</scope>
</dependency>

2、创建测试类,并使用TestNG的注解来定义测试方法和测试套件

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class SeleniumTestNGExample {
    private WebDriver driver;
    @BeforeMethod
    public void setUp() {
        // 设置WebDriver路径
        System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
        // 初始化WebDriver
        driver = new ChromeDriver();
    }
    @Test
    public void testGoogleSearch() {
        // 打开Google首页
        driver.get("https://www.google.com");
        // 执行测试逻辑
    }

    @AfterMethod
    public void tearDown() {
        // 关闭浏览器
        driver.quit();
    }
}

3、运行测试

在命令行中运行:

testng path/to/your/test-class/SeleniumTestNGExample.java

4、使用TestNG的高级功能

  • @BeforeSuite 和 @AfterSuite:在测试套件开始前和结束后执行。
  • @BeforeTest 和 @AfterTest:在每个测试类的所有测试方法执行前和执行后执行。
  • @BeforeClass 和 @AfterClass:在同一个类中的所有测试方法执行前和执行后执行。
  • @BeforeMethod 和 @AfterMethod:在每个测试方法执行前和执行后执行。
  • @Test:标记一个方法为测试方法,可以指定测试的优先级、依赖关系等。

十、selenium的面试题

  • 什么是selenium,工作原理是啥
Selenium 是一个开源的自动化测试框架,专门用于Web应用程序的测试。它支持多种编程语言,如Java、C#、Python、Ruby等,并提供了不同的工具和库来模拟用户在浏览器中的交互行为
selenium的原理涉及到3个部分,分别是:浏览器、driver(一般我们都会下载driver)、client(也就是我们写的代码)
client其实并不知道浏览器是怎么工作的,但是driver知道,在selenium启动以后,driver其实充当了 服务器的角色,跟client和浏览器通信,client根据webdriver协议发送请求给driver,driver解析请求,并在浏览器上执行相应的操作,并把执行结果返回给client。这就是selenium工作的大致原理。
  • selenium由哪些组件构成,常见类型的驱动程序
Selenium IDE、Selenium RC、Selenium WebDriver 和 Selenium Grid
FireFoxDriver   InternetExplorerDriver   ChromeDriver   SafariDriver   OperaDriver AndroidDriver
  • selenium是如何驱动浏览器做各种操作的呢
1.对于每一条Selenium脚本,一个http请求会被创建并且发送给浏览器的驱动,最开始建立连接时服务端返回一个sessionid给客户端,后续的交互都是通过sessionid进行交互
2.浏览器驱动中包含了一个HTTP Server,用来接收这些http请求
3.HTTP Server接收到请求后根据请求来具体操控对应的浏览器
4.浏览器执行具体的测试步骤
5.浏览器将步骤执行结果返回给HTTP Server
6.HTTP Server又将结果返回给Selenium的脚本,如果是错误的http代码我们就会在控制台看到对应的报错信息。
  • webdriver的协议是什么?
client与driver之间的约定,无论client是使用java实现还是c#实现,只要通过这个约定,client就可以准确的告诉drier它要做什么以及怎么做。
webdriver协议本身是http协议,数据传输使用json。 这里有webdriver协议的所有endpoint,稍微浏览下就知道这些endpoints涵盖了selenium的所有功能。
  • page object设计模式 和 page factory
page object:简单来说就是用class去表示被测页面。在class中定义页面上的元素和一些该页面上专属的方法。
Page Factory 实际上是官方给出的java page object的工厂模式实现
  • 如何查找元素是否显示在屏幕上?
WebDriver通过isDisplayed(), isSelected(), isEnabled(),这三种方法判断Web元素的可见性,这类方法将返回结果是布尔类型;Web元素可以是按钮,下拉框,复选框,单选按钮,标签等。
①isDisplayed():
boolean b1 = driver.findElement(By.id(“XXX”)).isDisplayed();
②isSelected():
boolean b2 = driver.findElement(By.id(“XXX”)).isSelected();
③isEnabled():
boolean b3 = driver.findElement(By.id(“XXX”)).isEnabled();
  • selenium中如何判断元素是否存在?
selenium中没有提供原生的方法判断元素是否存在,一般我们可以通过定位元素+异常捕获的方式判断
  • selenium中hidden或者是display = none的元素是否可以定位到?
不可以,selenium不能定位不可见的元素。display=none的元素实际上是不可见元素
  • selenium自动化页面元素找不到存在异常的原因?
① 元素定位错误
② 页面加载时间过慢,需要查找的元素程序已经完成,单页面还未加载,此时可以加载页面等待时间
③ 有可能元素包含在iframe或者frame里面,需要切换。
  • selenium中如何保证操作元素的成功率?也就是说如何保证我点击的元素一定是可以点击的?
  • 当网速不好的情况下,使用合适的等待时间;
  • 被点击的元素一定要占一定的空间,因为selenium默认会去点这个元素的中心点,不占空间的元素算不出来中心点;
  • 被点击的元素不能被其他元素遮挡;
  • 被点击的元素不能在viewport之外,也就是说如果元素必须是可见的或者通过滚动条操作使得元素可见;
  • 判断元素是否是可以被点击的。
  • 如何去定位属性动态变化的元素?
属性动态变化是指该element没有固定的属性值,只能通过相对位置定位。
第一种方法:用findelements遍历
第二种方法:通过xpath的轴 parent / following-sibling / precent-sibling
  • 如何去定位页面上动态加载的元素?
触发动态事件,继而findelement;如果是动态菜单,需要一级一级的find。
  • selenium调用js(execute_script),有哪些场景?
① 对input执行输入 ② 对富文本框的操作 ③ 滚动到指定位置操作
  • selenium如何处理web弹窗?js弹窗?
使用driver.switch_to.alert()
  • selenium是否支持桌面应用软件的自动化测试
不支持。selenium是根据网页元素的属性来确定范围元素的
  • 如何在webdriver中调用应用程序?
driver.get(‘url’) 或者 driver.navigate().to(‘url’)
  • selenium中常见的异常?
  • NoSuchElementException - 元素未找到异常
  • ElementNotVisibleException - 元素不可见异常
  • ElementNotSelectableException - 元素不可选择异常
  • NoAlertPresentException - 未找到警报异常
  • NoSuchAttributeException - 未找到属性异常
  • NoSuchWindowException - 未找到窗口异常
  • TimeoutException - 超时异常
  • WebDriverException - WebDriver异常
  • selenium为什么不推荐使用xpath定位?
selenium使用xpath定位时采用遍历页面的方式,性能指标较差。另外xpath定位有通过绝对路径定位的,有时会不准确;
而用css选择器定位比较简洁,运行速度更快,通常用于性能要求严格的场景。
  • 如何判断一个页面上元素是否存在?
1:用try…except 在代码块加上
2:用elements定义组元素方法 然后根其元素个数len()<1 存在返回True, 不存在则返回False
3:结合WebDriverWait和excepted_conditions条件判断(强烈推荐)
显示等待,每间隔1秒判断一次,30秒超时,存在返回True,不存在则返回False
  • 如何定位动态元素?
一个是属性动态,定位时,若id是动态的,就不要用id定位,用其他定位元素方法
另一个还是这个元素一会在页面上方,一会在下方,飘忽不定,定位方法也是一样,根据元素属性定位(元素的tag name属性是不会变的,动的只是class属性和style属性)
  • 如何通过子元素定位父元素?
第一种:通过子元素定位父元素,selenium提供了parent方法,但是只能定位到父元素,却不能获取元素属性,也不能操作。
第二种:通过xpath的语法直接定位。 如.//*[@name=”hello”]/.. 两个点代表父级元素。
  • 如何截取一个元素的图片,不要截取全部图片?
首选截取当前页面并自定义保存
然后根据要截取元素图片的属性来获取该元素的坐标和大小 ele.location ele.size
然后分别left = ele.location[‘x’] top = ele.location[‘y’] right = ele.location[‘x’] + ele.size[‘width’] bottom = ele.location[‘y’] + ele.size[‘height’]
获取该元素的图片的坐标大小
最后,再次打开刚开始保存的,通过image类中的crop方法(相当于拷贝该元素的一个矩形区域),然后做保存操作就可以了。
  • 一个元素明明定位了,点击无效(也没报错),如何解决?
使用js点击,selenium有时候点击元素时会失效
# js 点击
js = ‘document.getElementById(‘baidu’).click()’
driver.execute_script(js)
  • 如何提高selenium脚本的执行速度?
使用更高配置的电脑和选择更快的网络环境;
使用效率更高的语言,比如java执行速度就快过python;
优化代码;
不要盲目的加sleep,尽量使用显式等待;
可以考虑分布式执行(如,配置testNG实现多线程)或者使用selenium grid;
对于firefox,考虑使用测试专用的profile,因为每次启动浏览器的时候firefox会创建1个新的profile,对于这个新的profile,所有的静态资源都是从服务器直接下载,而不是从缓存里加载,这就导致网络不好的时候用例运行速度特别慢的问题;
chrome浏览器和safari浏览器的执行速度看上去是最快的。
  • 如何提高脚本的稳定性?
首先只要页面一直没变过,说明定位方法是没问题的。
优化方向:① 自己写相对路径,多用id为节点查找,少用右键复制xpath,那种不稳定。
② 第二个影响因素就是等待了,sleep等待尽量少用(影响执行时间) 尽量使用显式等待
③ 定位元素方法重新封装,结合WebDriverWait和excepted_conditions判断元素方法,自己封装一套定位元素方法
④ 尽量使用测试专用环境,避免其他类型的测试同时进行,对数据造成干扰
  • id,name,clas,xpath,css selector这些定位器,你最偏爱哪一种,为什么?
xpath和css最为灵活。id、name等需要开发支持
xpath定位时采用遍历页面的方式,性能指标较差。xpath定位有通过绝对路径定位的,有时会不准确;对于动态元素可以使用xpath
css选择器定位比较简洁,运行速度更快,通常用于性能要求严格的场景。
  • 登录按钮除了click之外还有什么方法
使用submit()方法,但它只能在属性type=submit时使用
  • 如何验证复选框/单选框是否被选中
driver.findElement(By.xpath("元素路径")).isSelected();
  • selenium自动化时,在平时遇到过哪些问题?如何解决的?
动态id 、有iframe的情况、没加等待等因素
  • selenium中隐藏元素定位,你该如何做?
隐藏元素可以正常定位到,只是不能操作(定位元素和操作元素是两码事,操作元素是指click 、clear 、send_keys等这些方法)。我们可以用js来操作隐藏元素。js和selenium不同,只有页面上有的元素(在dom里面的)都能正常操作。
  • 上传图片的几种方式?
send_keys和AutoIT工具实现.
  • 截图应当怎么操作?
driver.get_screenshot_as_file(‘C:\test.jpg’)
  • Assert和Verify有什么区别?
Assert和Verify都是用于验证结果。如果测试用例失败,那么Assert将停止测试用例的执行,并且不再往下执行后续的测试步骤。
对于Verify如果测试用例失败,都不会停止当前的程序执行,并且所有测试步骤都将被执行到。
  • 如何使用WebDriver执行右键单击?
// contextClick方法用于模拟右键单击操作。perform方法用于执行链中存储的所有操作
Actions actions = new Actions(driver);
actions.contextClick(element).perform();
  • 如何使用WebDriver执行拖放?
// dragAndDrop方法用于模拟从源元素拖放到目标元素的操作。perform方法用于执行链中存储的所有操作
Actions actions = new Actions(driver);
actions.dragAndDrop(sourceElement, targetElement).perform();
  • 举例Selenium中重载的方法
// 方法一:通过 iframe的索引值,在页面中的位置
driver.switchTo().frame(index);
// 方法二:通过 iframe 的name 或者id
driver.switchTo().frame(nameOrId);
// 方法三:通过iframe 对应的webElement
driver.switchTo().frame(frameElement);
  • 如何获取当前页面的URL
driver.getCurrentUrl();
  • 单斜杠和双斜杠有什么区别
/用于标识直接子节点
//用于在整个结构中查找
  • findElement和findElements有什么区别?
这两个方法都是WebDriver接口的抽象方法,用于在网页中查找元素。
findElemen():用于查找一个Web元素。它只返回一个WebElement类型。
findElements():用于查找多个Web元素。它返回WebElements集合。
  • 如何从文本框中获取输入的文本?
String text = driver.findElement(By.xpath("元素路径 ")).getAttribute("value"));
  • selenium webdriver有什么优点
1.主流浏览器如Chrome、Firefox、IE、Safari等,可以在不同浏览器上运行和测试应用。
2.支持大多数语言,如Java,Python,Ruby,C#等。
3.Selenium提供了丰富的API可以根据测试需求进行扩展,实现定制化的测试用例。
4.Selenium可以很好地与Jenkins,测试管理工具等集成,实现自动化测试的持续集成和持续交付。
  • 什么是Selenium Grid?
Selenium-Grid允许在不同的机器上针对不同的浏览器并行运行测试。也就是说,在不同的机器、不同的浏览器和操作系统上同时运行多个测试。本质上,Selenium-Grid支持分布式测试执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值