java - selenium 自动化入门

Selenium简介

selenium 是一种用于Web应用程序自动化测试的工具,直接运行在浏览器中,模拟用户操作,它支持多种浏览器(Chrome,Firebox,IE等),还支持多种语言编写测试脚本(Java,Python,Go等)。

因为我要做的最终脚本可以在win和mac上运行,并且不需要安装特定语言的环境,所以这里采用Java进行脚本编写,使用java多个平台代码统一,并且只要把jre打包即可,即可在别的电脑上运行(虽然jre也挺大,但是起码不用像node,python安装环境)。

安装selenium

第一步肯定是安装selenium依赖,可以通过下载jar包,或者通过maven引入。

这里使用 maven 管理项目依赖,所以在pom.xml添加以下依赖:

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

获取浏览器驱动

想用selenium驱动不同的浏览器需要不同的浏览器驱动,这里将会使用Chrome浏览器进行自动化测试,所以需要下载 ChromeDriver ,需要下载与目标浏览器相匹配的版本号的驱动器(不过Chrome浏览器一般都会自动更新,所以直接下载最新版的驱动器就是了)。

使用selenium打开浏览器

package org.example;

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

/**
 * Hello selenium!
 */
public class App {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        try {
            driver.get("https://www.baidu.com");
            driver.findElement(By.id("kw")).sendKeys("selenium" + Keys.ENTER);
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            driver.quit();
        }
    }
}

这里驱动器打开了浏览器后输入网址 https://www.baidu.com 并且找到了 id 为 kw 的节点,输入 selenium 按下回车键,最后休眠两秒钟。

这里就使用到了前面下载的 ChromeDriver,你需要把下载的 ChromeDriver 加载到系统path里,这里的程序才可以正常运行。

使用指定的 ChromeDriver 启动程序

不过前面说了我最终的用户电脑上并不会装有一些特定的环境,所以我打包给他的东西应该包含程序启动必要的所有东西:

  1. JRE
  2. ChromeDriver
  3. 启动脚本

所以这里我把下载到的 chromedriver 文件放到项目的 resources 目录下,并且让应用程序使用指定的 chromedriver :

package org.example;

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

import java.io.File;
import java.net.URL;

/**
 * Hello selenium!
 */
public class App {
    public static void main(String[] args) {
        URL chromeDriverUrl = App.class.getClassLoader().getResource("chromedriver");
        if (chromeDriverUrl == null) {
            throw new RuntimeException("缺少Chrome驱动器");
        }
        ChromeDriverService service = new ChromeDriverService.Builder()
                .usingDriverExecutable(new File(chromeDriverUrl.getPath()))
                .build();
        WebDriver driver = new ChromeDriver(service);
        try {
            driver.get("https://www.baidu.com");
            driver.findElement(By.id("kw")).sendKeys("selenium" + Keys.ENTER);
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            driver.quit();
        }
    }
}

如果正常的话,你现在运行程序应该可以看到程序自动打开百度,然后搜索 selenium 两秒之后就关闭浏览器。

控制浏览器大小,位置

package org.example;

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;

import java.io.File;
import java.net.URL;

/**
 * Hello selenium!
 */
public class App {
    public static void main(String[] args) {
        URL chromeDriverUrl = App.class.getClassLoader().getResource("chromedriver");
        if (chromeDriverUrl == null) {
            throw new RuntimeException("缺少Chrome驱动器");
        }
        ChromeDriverService service = new ChromeDriverService.Builder()
                .usingDriverExecutable(new File(chromeDriverUrl.getPath()))
                .build();
        WebDriver driver = new ChromeDriver(service);
        try {
            driver.get("https://www.baidu.com");
            driver.manage().window().maximize();// 最大化
//            driver.manage().window().fullscreen();// 全屏
//            driver.manage().window().setSize(new Dimension(800, 600));// 自定义浏览器大小
//            driver.manage().window().setPosition(new Point(0, 0));// 自定义浏览器左上角的位置
            driver.findElement(By.id("kw")).sendKeys("selenium" + Keys.ENTER);
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
//            driver.close();// 关闭当前窗口,如果当前窗口是最后一个窗口则,关闭浏览器
            driver.quit();// 关闭浏览器
        }
    }
}

控制浏览页跳转

我们浏览网页时可能会进行回退操作,点错了按钮啥情况的,还有刷新页面,往前翻页等操作。selenium也提供了这一系列操作:

driver.navigate().back();// 返回上一个页面
driver.navigate().forward();// 往前一个页面
driver.navigate().refresh();// 刷新当前页面
driver.navigate().to("https://www.csdn.net");// 前往另一个网址

页面元素操作

自动化测试就是在模拟人对浏览器的操作,我们一般都会在页面上输入信息,点击某个按钮。

如果写过网页的就应该知道网页是由 HTML 编写的,里面都是一些 dom 元素,加上 css 样式,变成了我们所看到的样子。

比如我们打开百度,然后在搜索框输入要搜索的信息,最后点击搜索(或者按回车键),最后百度就会把我们输入信息的相关数据都在网页上显示出来。

这里如果用selenium来进行自动化操作,那么需要分成四个步骤:

  1. 打开 https://www.baidu.com
  2. 找到输入框元素
  3. 在输入框元素中写入要查询的信息
  4. 找到百度一下这个按钮
  5. 点击按钮

打开指定网址

这个在上面的示例应该可以看到,就是通过 driver.get("https://www.baidu.com") 打开百度网址。

查找指定元素

这里我们可以先打开百度然后打开开发者工具(windows按 F12 ,mac 按 fn + F12
在这里插入图片描述
先观察页面的元素,可以看到这个输入框元素 <input> 具有:

  1. class: s_ipt
  2. name: wd
  3. id: kw

然后我们还需要验证 class="s_ipt" 的元素是否只存在一个,毕竟一个 class 可以给很多元素用。
在这里插入图片描述
我们需要打开网页框架源代码,然后搜索 class="s_ipt
在这里插入图片描述
可以看到 class="s_ipt" 的元素只有一个,说明我们可以通过 class 获取到输入框这个元素。

你也可以观察另外的 name="wd"id="kw" 是否也只有一个。

一般一个页面中 id 都是唯一的,正常开发者都是这么做的,不过以前写html的时候,好像同一个id用在两个元素上好像也是可以的,虽然报错了,但是页面还是能正常显示…所以就算是id也检查一下是否在这个页面上是唯一的。

代码示例

package org.example;

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;

import java.io.File;
import java.net.URL;

/**
 * Hello selenium!
 */
public class App {
    public static void main(String[] args) {
        URL chromeDriverUrl = App.class.getClassLoader().getResource("chromedriver");
        if (chromeDriverUrl == null) {
            throw new RuntimeException("缺少Chrome驱动器");
        }
        ChromeDriverService service = new ChromeDriverService.Builder()
                .usingDriverExecutable(new File(chromeDriverUrl.getPath()))
                .build();
        WebDriver driver = new ChromeDriver(service);
        try {
            // 1. 打开百度
            driver.get("https://www.baidu.com");
            // 2. 通过id找到输入框
            WebElement inputElement = driver.findElement(By.id("kw"));
            // 3. 在输入框中写入文字
            inputElement.sendKeys("selenium");
            // 4. 通过id找到'百度一下'按钮
            WebElement searchButton = driver.findElement(By.id("su"));
            // 5. 点击'百度一下'按钮
            searchButton.click();
            // 休眠两秒钟
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            driver.close();
        }
    }
}

如果你这里把 kw 写成了 km ,那么页面上不存在这个元素,此时程序就会报错:

Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"#km"}

查找元素的方式

通过id查找元素

上面的示例演示了通过 id 查找一个元素:By.id("kw")

通过class来查找元素

我们也可以通过 class 来查找输入框元素:By.className("s_ipt")

通过name来查找元素

我们也可以通过 name 来查找输入框元素:By.name("wd")

通过css选择器来查找元素

有时候我们会遇到比较复杂的页面,然后要查找的元素又没有唯一标识(可能有class但是有很多地方使用到这个class,没有id等情况)
在这里插入图片描述
例如我们要查找 https://mp.weixin.qq.com/ 的使用账号登录这个元素,我们可以看到这里只有 class="login__type__container__select-type" 但是通过网页源码查看

在这里插入图片描述
我们却看到了有三处类似,两个元素使用了这个class,说明我们无法使用这个 class 直接定位一个元素。

但是经过我们发现:这个元素的父级的class是唯一的 class="login__type__container login__type__container__scan" 所以我们可以通过css选择器来查找元素:By.cssSelector(".login__type__container.login__type__container__scan>.login__type__container__select-type")

抓取百度热榜简单示例

在这里插入图片描述

我们每次百度搜索时,都可以在右边看到一个百度热榜,我们就可以通过selenium来抓取百度最新的热门新闻了(虽然好像抓取这个东西用selenium有点大材小用了,不过入门嘛,意思一下)

一般用这个自动化可以抓取一些比较复杂的。比如可能还需要账号登录,然后去不同的页面抓取不同的数据,每个页面可能需要通过点击某个按钮才会显示出的一些数据,就是这种比较复杂的,用selenium会比较方便些。

package org.example;

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.net.URL;
import java.util.List;

/**
 * Hello selenium!
 */
public class App {
    public static void main(String[] args) {
        URL chromeDriverUrl = App.class.getClassLoader().getResource("chromedriver");
        if (chromeDriverUrl == null) {
            throw new RuntimeException("缺少Chrome驱动器");
        }
        ChromeDriverService service = new ChromeDriverService.Builder()
                .usingDriverExecutable(new File(chromeDriverUrl.getPath()))
                .build();
        WebDriver driver = new ChromeDriver(service);
        // 等待操作最多等待10秒
        WebDriverWait webDriverWait = new WebDriverWait(driver, 10);
        try {
            driver.get("https://www.baidu.com");
            driver.findElement(By.name("wd")).sendKeys("selenium" + Keys.ENTER);
            // 等待百度热榜数据出现(最多等待10秒)
            WebElement hotDataParentElement = webDriverWait
                    .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".c-table.opr-toplist1-table>tbody")));
            List<WebElement> hotDataElement = hotDataParentElement.findElements(By.tagName("tr"));
            for (WebElement element : hotDataElement) {
                WebElement rankElement = element.findElement(By.cssSelector("td>span>span"));
                WebElement titleElement = element.findElement(By.cssSelector("td>span>a"));
                System.out.println(rankElement.getText() + "、" + titleElement.getText());
            }
            driver.navigate().back();// 返回上一个搜索页面
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            driver.close();
        }
    }
}

因为这里搜索后会跳转页面,页面在重新渲染,所以需要使用 WebDriverWait (第二个参数就是最长等待时间秒数)来查找页面元素,如果直接用 driver.findElement() 那么程序会直接报错找不到元素。

打包可执行jar包(包含依赖)

参考教程:https://www.cnblogs.com/huahua035/p/11988631.html

最后打包出来的东西应该类似这样子:
在这里插入图片描述

我们只要执行那个 fl-auto.jar 即可:java -jar fl-auto.jar

运行可能会出现错误:

Exception in thread "main" java.lang.IllegalStateException: The driver executable does not exist: /Users/mac/workspace/code/idea/fl-auto/out/artifacts/fl_auto_jar/file:xxxxxxxx/fl-auto/out/artifacts/fl_auto_jar/fl-auto.jar!/chromedriver

这是找不到 chromedriver 的原因,虽然我们打出来的 jar 中是包含 chromedriver 文件的。

usingDriverExecutable(File file) 参数只接收 File 参数,打包出来的 chromedriver 存在 jar 包之中,所以得到的路径就很奇怪,这里可以改进一下获取 chromedriver 的方法:

package org.example;

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.net.URL;
import java.util.List;

/**
 * Hello selenium!
 */
public class App {
    public static void main(String[] args) {
        ChromeDriverService service = new ChromeDriverService.Builder()
                .usingDriverExecutable(new File(getChromeDriverPath(args)))
                .build();
        WebDriver driver = new ChromeDriver(service);
        // 最多等待10秒
        WebDriverWait webDriverWait = new WebDriverWait(driver, 10);
        try {
            driver.get("https://www.baidu.com");
            driver.findElement(By.name("wd")).sendKeys("selenium" + Keys.ENTER);
            // 等待百度热榜数据出现(最多等待10秒)
            WebElement hotDataParentElement = webDriverWait
                    .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".c-table.opr-toplist1-table>tbody")));
            List<WebElement> hotDataElement = hotDataParentElement.findElements(By.tagName("tr"));
            for (WebElement element : hotDataElement) {
                WebElement rankElement = element.findElement(By.cssSelector("td>span>span"));
                WebElement titleElement = element.findElement(By.cssSelector("td>span>a"));
                System.out.println(rankElement.getText() + "、" + titleElement.getText());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            driver.close();
        }
    }

    private static String getChromeDriverPath(String[] args) {
        String path = null;
        // 传入参数指定chromedriver路径
        if (args != null && args.length > 0) {
            path = args[0];
        }
        // 根目录下是否存在chromedriver
        if (path == null || path.isEmpty()) {
            File file = new File("chromedriver");
            if (file.exists()) {
                path = "chromedriver";
            }
        }
        // resources 下的chromedriver(开发时用到)
        if (path == null || path.isEmpty()) {
            URL chromeDriverUrl = App.class.getClassLoader().getResource("chromedriver");
            if (chromeDriverUrl == null) {
                throw new RuntimeException("Can't find chromedriver.");
            }
            path = chromeDriverUrl.getPath();
        }
        return path;
    }
}

当我们开发时就是直接获取 resources 目录下的 chromedriver ,而打包出来的jar可以通过给定指定路径,例如 java -jar fl-auto.jar /Users/mac/fl-auto/src/main/resources/chromedriver

或者把 chromedriver 放到打包后的根目录下:

在这里插入图片描述

然后在运行:java -jar fl-auto.jar 即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值