Selenium入门详细教程+实例演示

目录

1.Selenium概述

   1.1什么是Selenium

   1.2Selenium的优势

   1.3Selenium WebDriver原理

2.Selenium环境搭建

3.Selenium 简单示例

4.八大元素定位

   4.1定位方式

   4.2定位方式的用法

5.Selenium API

   5.1WebDriver 常用 API

   5.2WebElement 常用 API

   5.3代码示例

6.元素等待机制

   6.1硬性等待

   6.2隐式等待

   6.3显式等待

   6.4页面加载超时设置

7.弹出框处理(alert,confirm)

8.控制浏览器操作

9.模拟鼠标键盘操作

10.操作javaScript代码


1.Selenium概述

   1.1什么是Selenium

Selenium 是一种开源工具,用于在 Web 浏览器上执行自动化测试(使用任何 Web 浏览器进行 Web 应用程序测试)。提供一套测试函数,用于支持Web自动化测试。函数非常灵活,能够完成界面元素定位、窗口跳转、结果比较。重申一下,Selenium 仅可以测试Web应用程序我们既不能使用 Selenium 测试任何桌面(软件)应用程序,也不能测试任何移动应用程序。

具有如下特点:

  • 多浏览器支持
    • 如IE、Firefox、Safari、Chrome、Android手机浏览器等。
  • 支持多语言
    • 如Java、C#、Python、Ruby、PHP等。
  • 支持多操作系统
    • 如Windows、Linux、IOS、Android等。
  • 开源免费
    • 官网:Selenium

   1.2Selenium的优势

由于 Selenium 是开源的,因此不涉及许可费用,这是与其他测试工具相比的主要优势。当然Selenium 日益流行的其他原因是:

  • 测试脚本可以用以下任何一种编程语言编写:JavaPythonC#PHPRubyPerl 和 .Net
  • 可以在以下任何操作系统中进行测试:WindowsMac 或 Linux
  • 可以使用任何浏览器进行测试:Mozilla FirefoxInternet ExplorerGoogle ChromeSafari 或 Opera
  • 可以与 TestNG 和 JUnit 等工具集成,以管理测试用例和生成报告
  • 可以与 MavenJenkins 和 Docker 集成以实现持续测试

有优点当然也会存在缺点

  • 我们只能使用 Selenium 来测试 Web 应用程序。我们无法测试桌面应用程序或任何其他软件
  • 没有针对 Selenium 的保证支持。我们需要利用现有的客户社区
  • 无法对图像进行测试。我们需要将 Selenium 与 Sikuli 集成以进行基于图像的测试
  • 没有本机报告工具。但是我们可以通过将其与 TestNG 或 JUnit 之类的框架集成来解决该问题

   1.3Selenium WebDriver原理

只看图是不是有点模糊,我们可以用一个例子结合来理解:

将 WebDriver 驱动浏览器类比成开出租车的场景。

在开出租车时有三个角色

  • 乘客:他/她告诉出租车司机去哪里,大概怎么走。

  • 出租车司机:他按照乘客的要求来操控出租车。

  • 出租车:出租车按照司机的操控完成真正的行驶,把乘客送到目的地。

 

在WebDriver中也有类似的三个角色:

  • 工程师写的自动化测试代码:自动化测试代码发送请求给浏览器的驱动(比如火狐驱动、谷歌驱动)
  • 浏览器的驱动:它来解析这些自动化测试的代码,解析后把它们发送给浏览器
  • 浏览器:执行浏览器驱动发来的指令,并最终完成工程师想要的操作。

 

 

2.Selenium环境搭建

我们以Java为例,浏览器驱动以chrome为例

1.首先下载浏览器对应版本驱动

先确定谷歌浏览器版本,打开浏览器,点击帮助、关于Google Chrome

 

查看浏览器版本

 

下载谷歌浏览器对应版本驱动 

下载地址:http://chromedriver.storage.googleapis.com/index.html

或CNPM Binaries Mirror

 

如果你的谷歌浏览器是115.0版本开头,因为是最新版 

链接:Chrome for Testing availability
点击链接,找到对应版本的驱动,复制链接下载即可。
突然的升级,淘宝镜像找不到对应版本,可以git搜一下。

 

下载解压后设置浏览器驱动 

设置浏览器的地址非常简单。 我们可以手动创建一个存放浏览器驱动的目录,如: C:\driver , 将下载的浏览器驱动文件(例如:chromedriver、geckodriver)丢到该目录下。
我的电脑–>属性–>系统设置–>高级–>环境变量–>系统变量–>Path,将“C:\driver”目录添加到Path的值中。

验证浏览器驱动

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.opera.OperaDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;


WebDriver driver = new ChromeDriver();    //Chrome浏览器

WebDriver driver = new FirefoxDriver();   //Firefox浏览器

WebDriver driver = new EdgeDriver();      //Edge浏览器

WebDriver driver = new InternetExplorerDriver();  // Internet Explorer浏览器

WebDriver driver = new OperaDriver();     //Opera浏览器

WebDriver driver = new PhantomJSDriver();   //PhantomJS
 

3.Selenium 简单示例

我们示例以打开百度进行搜索:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;


public class BaiduSearch {
    public static void main(String[] args) {
        // 1.创建webdriver驱动
        WebDriver driver = new ChromeDriver();
        // 2.打开百度首页
        driver.get("https://www.baidu.com");
        // 3.获取输入框,输入selenium
        driver.findElement(By.id("kw")).sendKeys("selenium");
        // 4.获取“百度一下”按钮,进行搜索
        driver.findElement(By.id("su")).click();
        // 5.退出浏览器
        driver.quit();
    }
}

4.八大元素定位

为什么要进行元素定位?

​ 我们必须告诉 selenium 怎么去定位元素,用来模拟用户的动作,或者查看元素的属性和状态,以便于我们可以执行检查。例如:我们要搜索一个产品,首先要找到搜索框与搜索按钮,接着通过键盘输入要查询的关键字,最后鼠标单击搜索按钮,提交搜索请求。

​ 正如上述的人工操作步骤一样,我们也希望 selenium 能模拟这样的动作,然而,selenium 并不能理解类似在搜索框中输入关键字或者点击搜索按钮这样的图形化的操作。所以需要我们程序化的告诉 selenium 如何定位搜索框和搜索按钮,从而模拟键盘和鼠标的操作。

   4.1定位方式

selenium 提供了8种的定位方式:

  • id
  • name
  • class name
  • tag name
  • link text
  • partial link text
  • xpath
  • css selector

这8种定位方式在java selenium 中对应的方法为:

同时这8种方法都对应有着返回复数元素的方法,分别在调用的方法findElements(By.id()) 加上一个s:

  • findElements(By.id())
  • findElements(By.name())
  • findElements(By.className())
  • findElements(By.tagName())
  • findElements(By.linkText())
  • findElements(By.partialLinkText())
  • findElements(By.xpath())
  • findElements(By.cssSelector())

   4.2定位方式的用法

假如我们有一个Web页面,通过前端工具查看到一个元素的属性是这样的。

<html>
  <head>
  <body link="#0000cc">
    <a id="result_logo" href="/" onmousedown="return c({'fm':'tab','tab':'logo'})">
    <form id="form" class="fm" name="f" action="/s">
      <span class="soutu-btn">按钮</span>
        <input id="kw" class="s_ipt" name="wd" value="" maxlength="255" autocomplete="off">

我们的目的是要定位input标签的输入框。

  • 通过id定位:
driver.findElement(By.id("kw"))
  • 通过name定位:
driver.findElement(By.name("wd"))
  • 通过class name定位:
driver.findElement(By.className("s_ipt"))
  • 通过tag name定位:
driver.findElement(By.tagName("input"))
  • 通过xpath定位,xpath定位有很多种写法,这里列几个常用写法:
driver.findElement(By.xpath("//*[@id='kw']")) // id定位
driver.findElement(By.xpath("//*[@name='wd']")) // 属性值定位
driver.findElement(By.xpath("//span[text()='按钮']")) // 文本定位
driver.findElement(By.xpath("//input[@class='s_ipt']")) // class属性定位
driver.findElement(By.xpath("/html/body/form/span/input")) // 绝对路径定位
driver.findElement(By.xpath("//span[@class='soutu-btn']/input")) // 相对路径定位
driver.findElement(By.xpath("//form[@id='form']/span/input"))
driver.findElement(By.xpath("//input[@id='kw' and @name='wd']")) // 多组合属性定位
driver.findElement(By.xpath("//span[contains(text(),'按钮')]")) // 是否包含文本
  • 通过css定位,css定位有N种写法,这里列几个常用写法(博主更推荐使用css):
driver.findElement(By.cssSelector("#kw") // id定位
driver.findElement(By.cssSelector("[name=wd]") // name属性值定位
driver.findElement(By.cssSelector(".s_ipt") // class地位
driver.findElement(By.cssSelector("html > body > form > span > input") // css层级定位
driver.findElement(By.cssSelector("span.soutu-btn> input#kw") 
driver.findElement(By.cssSelector("form#form > span > input")

接下来,我们的页面上有一组文本链接。 

<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
  • 通过linkText定位:
driver.findElement(By.linkText("新闻")
driver.findElement(By.linkText("hao123")
  • 通过 partialLinkText 定位:
driver.findElement(By.partialLinkText("新")
driver.findElement(By.partialLinkText("hao")
driver.findElement(By.partialLinkText("123")

5.Selenium API

   5.1WebDriver 常用 API

WebDriver 提供了一系列的 API 来和浏览器进行交互,如下:

 

   5.2WebElement 常用 API

 通过 WebElement 实现与网站页面上元素的交互,这些元素包含文本框、文本域、按钮、单选框、div等,WebElement提供了一系列的方法对这些元素进行操作:

   5.3代码示例

public class BaiduSearch {
    public static void main(String[] args) {
        // 1.创建webdriver驱动
        WebDriver driver = new ChromeDriver();
        // 2.打开百度首页
        driver.get("https://www.baidu.com");

        // 获取搜索框元素
        WebElement inputElem = driver.findElement(By.id("kw"));

        // clear()方法,清空输入框内容
        inputElem.clear();

        // sendKeys()方法,在搜索框中输入搜索内容
        inputElem.sendKeys("selenium");

        // 元素是否显示
        boolean displayed = inputElem.isDisplayed();
        System.out.println(displayed); // 输出true

        // 元素是否启用
        boolean enabled = inputElem.isEnabled();
        System.out.println(enabled); // 输出true
        
        // 判断元素是否被选中状态,一般用在Radio(单选),Checkbox(多选),Select(下拉选)
        // 在输入框中使用无意义
        boolean selected = inputElem.isSelected();
        System.out.println(selected); // 输出fasle
        
        // 获取标签名
        String tagName = inputElem.getTagName();
        System.out.println(tagName); // 输出input

        // 获取属性名(name属性)
        String name = inputElem.getAttribute("name");
        System.out.println(name); // 输出wd
        
        // 获取文本值
        String text = inputElem.getText();
        System.out.println(text); // 输出selenium
        
        // 通过submit提交
        driver.findElement(By.id("su")).submit();
        
        // click()方法,点击百度一下按钮
        driver.findElement(By.id("su")).click();

        // 退出浏览器
        driver.quit();
    }
}

6.元素等待机制

在对元素进行定位时,有时候网页加载时间比较长,元素还没有加载出来,这个时候去查找这个元素的话程序中就会抛出异常,所以我们在编写代码时需要考虑延时问题,在selenium中有几种延时机制可以使用如下:

   6.1硬性等待

​ 硬性等待就是不管你浏览器元素是否加载完成,都要进行等待设置好的时间,利用 java 语言中的线程类 Thread 中的 sleep 方法,进行强制等待。

Thread.sleep(long millis)

该方法会让线程进行休眠

如:Thread.sleep(3000) 表示程序执行的线程暂停 3 秒钟。

​ 这种方法在一定的程度上是可以解决元素加载过慢的情况,但是不建议使用该方法,因为一般情况下我们无法判断网页到底需要多长时间加载完成,如果我们设置的时间过长,非常影响效率。

   6.2隐式等待

隐式等待的理解,就是我们通过代码设置一个等待时间,如果在这个等待时间内,网页加载完成后就执行下一步,否则一直等待到时间截止。

代码表示:

driver.manage.timeouts.implicitlyWait(long time, TimeUtil unit);

​ 这种方法相对于硬性等待显的会灵活一点,但是隐式等待也有个弊端,因为这个设置是全局的,程序需要等待整个页面加载完成,直到超时,有时候我需要找的那个元素早就加载完成了,只是页面上有个别其他元素加载比较慢,程序还是会一直等待下去。直到所有的元素加载完成在执行下一步。 

   6.3显式等待

显示等待是等待指定元素设置的等待时间,在设置时间内,默认每隔0.5s检测一次当前的页面这个元素是否存在,如果在规定的时间内找到了元素则执行相关操作,如果超过设置时间检测不到则抛出异常。默认抛出异常为:NoSuchElementException。推荐使用显示等待。

代码表示:

WebDriberWait wait = new WebDriverWait(dirver, timeOutInSeconds);
wait.nutil(expectCondition);

具体使用案例:

1.查找元素是否已经加载出来

WebDriverWait wait = new WebDriverWait(driver, 5);
// 查找id为“kw"的元素是否加载出来了(已经在页面DOM中存在)
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("kw")));

// 在设定时间内找到后就返回,超时直接抛异常

2.查找元素是否可见 

WebDriverWait wait = new WebDriverWait(driver, 5);
// 查找id为"kw"的元素是否可见
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("kw")));

3.查找元素是否可点击 

WebDriverWait wait = new WebDriverWait(driver, 5);
// 查找id为"kw"的元素是否可以点击
wait.until(ExpectedConditions.elementToBeClickable(By.id("kw")));

   6.4页面加载超时设置

通过TimeOuts 对象进行全局页面加载超时的设置,该设置必须放置get 方法之前。如下代码

driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
driver.get("https://www.baidu.com");

如果百度首页在超过5秒钟没有加载完毕,程序就会抛出异常,如果在 2秒就加载完了,就直接往下执行,如果需要对页面加载时间有要求的,可以用这个设置进行检验。 

7.弹出框处理(alert,confirm)

7.1操作alert、confirm弹出框,可以通过Alert 对象来进行操作,Alert类包含了确认、取消、输入和获取弹出窗内容。

Alert对应属性和方法:

 

简单使用示例: 

// 首先需要切换到弹出框中,获取Alert对象。
Alert alert = driver.switchTo().alert();
// 获取弹窗文本内容
alert.getText();
// 点击确定按钮
alert.accept();
// 点击取消按钮
alert.dismiss();

7.2iframe 切换 :

有时候我们定位元素的时候,发现怎么都定位不了。 这时候你需要查一查你要定位的元素是否在iframe里面。

什么是iframe?

iframe 就是HTML 中,用于网页嵌套网页的。 一个网页可以嵌套到另一个网页中,可以嵌套很多层。

例如:

main.html

<html>
<head>
  <title>FrameTest</title>
</head>
<body>
  <div id="id1">this is main page's div!</div>
  <input type="text" id="maininput" />
  <br/>
  <iframe id="frameA" frameborder="0" scrolling="no" style="left:0;position:absolute;" src="frame.html"></iframe>
</body>
</html>

frame.html 

<html>
<head>
  <title>this is a frame!</title>
</head>
<body>
  <div id="div1">this is iframes div,</div>
  <input id="iframeinput"></input>
</body>
</html>

使用selenium 操作浏览器时,如果需要操作iframe中的元素,首先需要切换到对应的内联框架中。

selenium 给我们提供了三个重载的方法,进行操作iframe;

// 方法一:通过 iframe的索引值,在页面中的位置
driver.switchTo().frame(index);
// 方法二:通过 iframe 的name 或者id
driver.switchTo().frame(nameOrId);
// 方法三:通过iframe 对应的webElement        
driver.switchTo().frame(frameElement);

selenium 代码: 

public static void testIframe(WebDriver driver){
    // 在 主窗口的时候
    driver.findElement(By.id("maininput")).sendKeys("main input");
    // 此时 没有进入到iframe, 以下语句会报错
    //driver.findElement(By.id("iframeinput")).sendKeys("iframe input");

    driver.switchTo().frame("frameA");
    driver.findElement(By.id("iframeinput")).sendKeys("iframe input");

    // 此时没有在主窗口,下面语句会报错
    //driver.findElement(By.id("maininput")).sendKeys("main input");

    // 回到主窗口
    driver.switchTo().defaultContent();
    driver.findElement(By.id("maininput")).sendKeys("main input"); 
}

注:如果已经切换进入了其中的一个 iframe 中,再想对 iframe 外的元素进行操作,需要切换回到默认的页面中,否则会找不到元素。 

// 切换到默认内容页面
driver.switchTo().defaultContent();

 7.3浏览器窗口的切换 

有时候后在操作浏览器,可能打开了一个新的窗口,这个时候如果要对新窗口的元素进行操作,需要切换到新窗口中去,怎么去切换呢?在 selenium 中有个叫句柄的概念。

​ 什么是句柄,简单理解就是浏览器窗口的一个标识,浏览器打开的每个窗口都有唯一的一个标识,也就是句柄,我们可以通过句柄来进行窗口之间的切换,从而来达到我们操作不同窗口的元素。

WebDriver 中提供了两个 API 来获取窗口的相关句柄:

// 获取当前窗口的句柄
String handle = driver.getWindowHandle();
// 获取所有窗口的句柄,返回一个集合
Set<String> handles = driver.getWindowHandles();

获取到句柄后,通过对应的方法进行切换: 

// 切换到窗口
driver.switchTo.windwo(String handle);

多窗口之间的切换方法: 

/**
* 切换窗口的方法
* 通过传入一个标题来找到我们需要的窗口。
* @param title 窗口的标题
*/
public void switchWindow(String title){
    Set<String> handles = driver.getWindowHandles();
    // 切换窗口的方式--循环遍历handles集合
    for (String handle : handles) {
        //判断是哪一个页面的句柄??--根据什么来判断???title
        if(driver.getTitle().equals(title)){
        break;
    }else{
        //切换窗口--根据窗口标识来切换
        driver.switchTo().window(handle);
    }
}

 7.4.select 下拉框处理

如果一个页面元素是一个下拉框(select),对应下拉框的操作,selenium有专门的类 Select 进行处理。其中包含了单选和多选下拉框的各种操作,如获得所有的选项、选择某一项、取消选中某一项、是否是多选下拉框等。 

Select类常用的一些方法:

示例:2345网址导航首页的城市省份切换。

1.进入2345.com首页,点击头部【切换】进行城市切换,我们切换省份为北京。

 

2.HTML页面DOM结构.

 

3.代码编写,这里需要注意下拉选是在一个iframe中,需要先切换到这个iframe后再操作。

 // 创建驱动
 WebDriver driver = new ChromeDriver();
 // 打开2345网站
 driver.get("https://www.2345.com");
 // 切换城市
 driver.findElement(By.linkText("切换")).click();
 // 切换到iframe内联框架中
 driver.switchTo().frame("city_set_ifr");
 // 定位到省份下拉框
 WebElement province = driver.findElement(By.id("province"));
 province.click();
 // 创建Select对象
 Select select = new Select(province);
 // 根据文本来获取下拉值
 select.selectByVisibleText("B 北京");
 driver.quit();

8.控制浏览器操作

WebDriver 给我们提供了一个 Window 对象,专门用于对窗口的设置。

对象获取方法:

Window window = driver.manage().window();

Window 对象的方法有: 

8.2.浏览器导航操作 

WebDriver 提供了 Navigation 对象来对浏览器进行导航操作,如:前进、后退、刷新等。

Navigation 对象获取:

Navigation navigate = driver.navigate();

Navigation 对象提供的方法: 

 

9.模拟鼠标键盘操作

模拟鼠标

在WebDriver中,关于鼠标的操作我们可以通过 Actions 类来模拟鼠标右击、双击、悬停、拖动等操作。

Actions 类中鼠标操作常用方法:

示例:百度首页设置悬停下拉菜单

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;

public class MouseDemo {

  public static void main(String[] args) {

    WebDriver driver = new ChromeDriver();
    driver.get("https://www.baidu.com/");
	// 定位元素
    WebElement search_setting = driver.findElement(By.linkText("设置"));
    // 创建actions对象
    Actions action = new Actions(driver);
    // 模拟鼠标悬停
    action.clickAndHold(search_setting).perform();

    driver.quit();
  }
}

10.操作javaScript代码

虽然WebDriver提供了操作浏览器的前进和后退方法,但对于浏览器滚动条并没有提供相应的操作方法。在这种情况下,就可以借助JavaScript来控制浏览器的滚动条。WebDriver提供了executeScript()方法来执行JavaScript代码。

用于调整浏览器滚动条位置的JavaScript代码如下:

<!-- window.scrollTo(左边距,上边距); -->
window.scrollTo(0,450);

window.scrollTo() 方法用于设置浏览器窗口滚动条的水平和垂直位置。方法的第一个参数表示水平的左间距,第二个参数表示垂直的上边距。其代码如下:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.JavascriptExecutor;

public class JSDemo {

  public static void main(String[] args) throws InterruptedException{

    WebDriver driver = new ChromeDriver();

    //设置浏览器窗口大小
    driver.manage().window().setSize(new Dimension(700, 600));
    driver.get("https://www.baidu.com");

    //进行百度搜索
    driver.findElement(By.id("kw")).sendKeys("webdriver api");
    driver.findElement(By.id("su")).click();
    Thread.sleep(2000);

    //将页面滚动条拖到底部
    ((JavascriptExecutor)driver).executeScript("window.scrollTo(100,450);");
    Thread.sleep(3000);

    driver.quit();
  }
}

通过浏览器打开百度进行搜索,并且提前通过 window().setSize() 方法将浏览器窗口设置为固定宽高显示,目的是让窗口出现水平和垂直滚动条。然后通过 executeScript() 方法执行JavaScripts代码来移动滚动条的位置。

将滚动条滚动到某个区域后停止(页面元素全部加载完成),如下:

//滚动到某一区域
//scrollIntoView(0);  让元素滚动到可视区域的最下方
//scrollIntoView();  让元素滚动到可视区域的最上方
//JavascriptExecutor javascriptExecutor = (JavascriptExecutor)BrowserUtil.driver;
//javascriptExecutor.executeScript("document.getElementById('index_ads').scrollIntoView(0);");
//JavaScript的参数传递-selenium和js的交互
//1、先去找到这个元素
WebElement webElement = driver.findElement(By.xpath("element"));
//2、找到的元素作为参数传入到Js代码中
JavascriptExecutor javascriptExecutor = (JavascriptExecutor)driver;
javascriptExecutor.executeScript("arguments[0].scrollIntoView(0)",webElement);

页面元素是通过懒加载方式,需要一直进行滚动的 

/**
* 滑动列表找元素并且进行点击(懒加载)
* @param selectedText  选中元素文本
* @param by  正在加载类似元素的定位表达式
*/
public static void clickElementInList(String selectedText, By by) {
    // 滑动之前的页面源代码信息
    String beforeSource = "";
    // 滑动之后的页面源代码信息
    String afterSource = "";
    // 循环条件
    // 1、找到了元素,跳出循环
    // 2、如果没有找到元素???怎么跳出循环
    while (true) {
        WebElement webElement = driver.findElement(by);
        // 获取页面源代码
        beforeSource = driver.getPageSource();
        // 获取js执行器
        JavascriptExecutor javascriptExecutor = (JavascriptExecutor)driver;
        // 执行js
        javascriptExecutor.executeScript("arguments[0].scrollIntoView(0);", webElement);
        
        // 如果当前页面有想要的元素,怎么判断是否有??--getPageSource
        if (driver.getPageSource().contains(selectedText)) {
            driver.findElement(By.linkText(selectedText)).click();
            // 找到元素退出循环,不再滚动。
            break;
        }

        afterSource = driver.getPageSource();
        // 页面元素没有变化---滑动到了最底部
        if (afterSource.equals(beforeSource)) {
            // 到达底部,退出。
            break;
        }

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/62592.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DNSlog注入(利用DNSlog平台将SQL盲注变成回显注入)

前言什么是UNC什么是DNSlog注入DNSlog注入的条件防止DNSlog注入的几个措施 sqli-labs试验 前言 前几天面试的时候&#xff0c;面试官问我知不知道OOB&#xff08;带外数据&#xff09;。 当时我蒙了&#xff0c;确实没听说过这个东西&#xff0c;然后面试官告诉我原来dnslog注入…

Vue3 第一节 Vue3简介以及创建Vue3工程

1.Vue3简介以及Vue3带来了什么 2.创建Vue3.0工程并分析Vue3工程结构 3.setup函数 4.ref函数 5.reactive函数 一.Vue3简介以及Vue3带来了什么 ① Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff0…

[腾讯云Cloud Studio实战训练营]基于Cloud Studio完成图书管理系统

[腾讯云Cloud Studio实战训练营]基于Cloud Studio完成图书管理系统 ⭐前言&#x1f31c;Cloud Studio产品介绍1.登录2.创建工作空间3.工作空间界面简介4.环境的使用 ⭐实验实操&#x1f31c;Cloud Studio实现图书管理系统1.实验目的 2. 实验过程2.实验环境3.源码讲解3.1添加数据…

postgresql 使用之 存储架构 触摸真实数据的存储结构以及组织形式,存入数据库的数据原来在这里

存储架构 ​专栏内容&#xff1a; postgresql内核源码分析 手写数据库toadb 并发编程 个人主页&#xff1a;我的主页 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 概述 postgresql 数据库服务运行时&#xff0c;数据在磁…

【IMX6ULL驱动开发学习】22.IMX6ULL开发板读取ADC(以MQ-135为例)

IMX6ULL一共有两个ADC&#xff0c;每个ADC都有八个通道&#xff0c;但他们共用一个ADC控制器 1.设备树 在imx6ull.dtsi文件中已经帮我们定义好了adc1的节点部分信息 adc1: adc02198000 {compatible "fsl,imx6ul-adc", "fsl,vf610-adc";reg <0x0219…

Jenkins工具系列 —— 插件 钉钉发送消息

文章目录 安装插件 Ding TalkJenkins 配置钉钉机器人钉钉APP配置项目中启动钉钉通知功能 安装插件 Ding Talk 点击 左侧的 Manage Jenkins —> Plugins ——> 左侧的 Available plugins Jenkins 配置钉钉机器人 点击 左侧的 Manage Jenkins &#xff0c;拉到最后 钉…

【Segment Anything Model】四:预处理自己的数据集接入SAM

文章目录 1️⃣预备知识2️⃣实现思路&#x1f538;脚本预处理得到包含embedd和GT的npz&#x1f538;编写Dataset类3️⃣代码&#x1f538;实现脚本预处理得到包含embedd和GT的npz代码&#x1f538;实现Dataset的代码 1️⃣预备知识 欢迎订阅本专栏&#xff08;为爱发电&#…

基于SPSSPRO实现层次分析法(AHP)

层次分析法&#xff0c;简称AHP&#xff0c;是指将与决策总是有关的元素分解成目标、准则、方案等层次&#xff0c;在此基础之上进行定性和定量分析的决策方法。&#xff08;摘自百度百科&#xff09; 层次分析法有着广泛使用&#xff0c;涉及到的平台也多种多样&#xff0c;今…

Android Studio新版本logcat过滤说明

按包名过滤 //输入package:&#xff08;输入一个p就会有提示的&#xff09; &#xff0c;后面加上包名 比如: package:com.xal.runcontrol package:包名可以完整或者输部分包名即可 package:包名需要输完整准确 package~:正则表达式过滤 不了解正则表达式的可以参考&#…

·[K8S:使用calico网络插件]:解决集群节点NotReady问题

文章目录 一&#xff1a;安装calico&#xff1a;1.1&#xff1a;weget安装Colico网络通信插件&#xff1a;1.2&#xff1a;修改calico.yaml网卡相关配置&#xff1a;1.2.1&#xff1a;查看本机ip 网卡相关信息&#xff1a;1.2.2&#xff1a;修改calico.yaml网卡interface相关信…

普及100Hz高刷+1ms响应 微星发布27寸显示器:仅售799元

不论办公还是游戏&#xff0c;高刷及低响应时间都很重要&#xff0c;微星现在推出了一款27寸显示器PRO MP273A&#xff0c; 售价只有799元&#xff0c;但支持100Hz高刷、1ms响应时间&#xff0c;还有FreeSync技术减少撕裂。 PRO MP273A的100Hz高刷新率是其最大的卖点之一&#…

使用node.js 搭建一个简单的HelloWorld Web项目

文档结构 config.ini #将本文件放置于natapp同级目录 程序将读取 [default] 段 #在命令行参数模式如 natapp -authtokenxxx 等相同参数将会覆盖掉此配置 #命令行参数 -config 可以指定任意config.ini文件 [default] authtokencc83c08d73357802 #对应一条隧…

Python绘制箭头向量图,并绘制三体引力场

文章目录 简介箭头设置三维场图 简介 箭头向量图十分常见&#xff0c;比如天气预报在显示风场的时候&#xff0c;就会贴心地用箭头指明风的方向。在matplotlib中&#xff0c;用quiver函数来绘制箭头向量图&#xff0c;示例如下 import matplotlib.pyplot as plt import numpy…

使用hexo进行博客迁移

本文不会从0开始介绍如何通过hexo去搭建一个github page。因为最近折腾了下&#xff0c;发现这玩意儿确实写个博客很费劲&#xff0c;打算把他拖管到github当作我的知识库网站&#xff0c;我的主要文章还是通过mweb写完一键发布到博客园&#xff0c;然后csdn记录一些杂文和思考…

PHP8的程序结构-PHP8知识详解

在做任何事情之前&#xff0c;都需要遵循一定的规则。在PHP8中&#xff0c;程序能够安照人们的意愿执行程序&#xff0c;主要依靠程序的流程控制语句。 不管多复杂的程序&#xff0c;都是由这些基本的语句组成的。语句是构造程序的基本单位。程序执行的过程就是执行程序语句的…

JVM 学习—— 类加载机制

前言 在上一篇文章中&#xff0c;荔枝梳理了有关Java中JVM体系架构的相关知识&#xff0c;其中涉及到的有关Java类加载机制的相关知识并没有过多描述。那么在这篇文章中&#xff0c;荔枝会详细梳理一下有关JVM的类加载机制和双亲委派模型的知识&#xff0c;希望能够帮助到有需要…

Android应用开发(6)TextView进阶用法

Android应用开发学习笔记——目录索引 上一章Android应用开发&#xff08;5&#xff09;文本视图&#xff08;TextView&#xff09;介绍了文本视图&#xff08;TextView&#xff09;设置文本内容、设置文本大小、设置文本显示颜色。 TextView是最基础的文本显示控件&#xff…

【STM32零基础入门教程03】GPIO输入输出之GPIO框图分析

本章节主要讲解点亮LED的基本原理&#xff0c;以及GPIO框图的讲解。 如何点亮LED&#xff08;输出&#xff09; 首先我们查看原理图&#xff0c;观察电路图中LED的连接情况&#xff0c;如下图可以看出我们的板子中LED一端通过限流电阻连接的PB0另一端连接的是高电平VCC&#xf…

召唤神龙打造自己的ChatGPT

在之前的两篇文章中&#xff0c;我介绍了GPT 1和2的模型&#xff0c;并分别用Tensorflow和Pytorch来实现了模型的训练。具体可以见以下文章链接&#xff1a; 1. 基于Tensorflow来重现GPT v1模型_gzroy的博客-CSDN博客 2. 花费7元训练自己的GPT 2模型_gzroy的博客-CSDN博客 有…

Rocketmq 定时消息源码分析

定时消息定义 生产者将消息投放到broker后&#xff0c;不会马上被消费者消费。需要等待到特定时间才会被消费。 调用链路 producer 将定时消息写入commitLog线程ReputThead 休息1毫秒&#xff0c;读取一次commitlog数据&#xff0c;写入ConsumeQueue和IndexFile线程Scheduled…