最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java+selenium實(shí)現(xiàn)滑塊驗(yàn)證

 更新時(shí)間:2023年12月12日 15:21:07   作者:越走越遠(yuǎn)的風(fēng)  
現(xiàn)在越來(lái)越多的網(wǎng)站都使用采用滑塊驗(yàn)證來(lái)作為驗(yàn)證機(jī)制,用于判斷用戶是否為人類而不是機(jī)器人,本文就將利用java和selenium實(shí)現(xiàn)滑塊驗(yàn)證,希望對(duì)大家有所幫助

背景

現(xiàn)在越來(lái)越多的網(wǎng)站都使用采用滑塊驗(yàn)證來(lái)作為驗(yàn)證機(jī)制,用于判斷用戶是否為人類而不是機(jī)器人。它需要用戶將滑塊拖動(dòng)到指定位置來(lái)完成驗(yàn)證。

網(wǎng)上上有很多python和node過(guò)滑塊的案例,但是java的特別少。

本篇文章一起來(lái)看下java怎么實(shí)現(xiàn)滑塊驗(yàn)證。

思路

因?yàn)殡[私問(wèn)題,假設(shè)有一個(gè)網(wǎng)站 www.example.com, 打開(kāi)后需要點(diǎn)擊,那么我們完整的登錄流程為:

  • 打開(kāi)網(wǎng)站www.example.com
  • 點(diǎn)擊頁(yè)面右上角login
  • 在彈出對(duì)話框輸入用戶名
  • 點(diǎn)擊send code 發(fā)送郵箱驗(yàn)證碼
  • 彈出滑塊,拖動(dòng)滑動(dòng)滑塊到指定位置,松開(kāi)鼠標(biāo)
  • 查看郵箱驗(yàn)證碼,并輸入
  • 點(diǎn)擊登錄
  • 獲取登錄后cookie中返回的token,判斷是否登錄成功

代碼

chromedriver下載地址

下載與自己瀏覽器對(duì)應(yīng)版本的chromedriverregistry.npmmirror.com/binary.html

最新版谷歌瀏覽器chromedriver下載地址googlechromelabs.github.io/chrome-for-testing/

maven增加如下依賴

<!-- selenium-java -->
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>4.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.15.1</version>
</dependency>
<!-- 獲取郵箱驗(yàn)證碼 -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>javax.mail-api</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>
<!-- 工具類 -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.22</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>

滑塊驗(yàn)證

  • 先保存無(wú)缺口的圖片到本地,然后保存有缺的圖片到本地。
  • 將兩張圖片轉(zhuǎn)換成RGB集合,比較兩張圖片像素點(diǎn)的RGB值是否相同。
  • 只要RGB的集合大于一定的誤差閾值,則認(rèn)為該位置為缺口位置。

核心代碼如下:

    /**
     * 比較兩張截圖,找出有缺口的驗(yàn)證碼截圖中缺口所在位置
     * 由于滑塊是x軸方向位移,因此只需要x軸的坐標(biāo)即可
     *
     * @return 缺口起始點(diǎn)x坐標(biāo)
     * @throws Exception
     */
    public int comparePicture() throws Exception {
        notchPicture = ImageIO.read(new File("有缺口.png"));
        fullPicture = ImageIO.read(new File("無(wú)缺口.png"));
        int width = notchPicture.getWidth();
        int height = notchPicture.getHeight();
        int pos = 70;  // 小方塊的固定起始位置
        // 橫向掃描
        for (int i = pos; i < width; i++) {
            for (int j = 0; j < height - 10; j++) {
                if (!equalPixel(i, j)) {
                    pos = i;
                    return pos;
                }
            }
        }
        throw new Exception("未找到滑塊缺口");
    }
    /**
     * 比較兩張截圖上的當(dāng)前像素點(diǎn)的RGB值是否相同
     * 只要滿足一定誤差閾值,便可認(rèn)為這兩個(gè)像素點(diǎn)是相同的
     *
     * @param x 像素點(diǎn)的x坐標(biāo)
     * @param y 像素點(diǎn)的y坐標(biāo)
     * @return true/false
     */
    public boolean equalPixel(int x, int y) {
        int rgbaBefore = notchPicture.getRGB(x, y);
        int rgbaAfter = fullPicture.getRGB(x, y);
        // 轉(zhuǎn)化成RGB集合
        Color colBefore = new Color(rgbaBefore, true);
        Color colAfter = new Color(rgbaAfter, true);
        int threshold = 220;   // RGB差值閾值
        if (Math.abs(colBefore.getRed() - colAfter.getRed()) < threshold &&
                Math.abs(colBefore.getGreen() - colAfter.getGreen()) < threshold &&
                Math.abs(colBefore.getBlue() - colAfter.getBlue()) < threshold) {
            return true;
        }
        return false;
    }

移動(dòng)滑塊代碼:

    /**
     * 移動(dòng)滑塊,實(shí)現(xiàn)驗(yàn)證
     *
     * @param moveTrace 滑塊的運(yùn)動(dòng)軌跡
     * @throws Exception
     */
    public void move(List<Integer> moveTrace) throws Exception {
        // 獲取滑塊對(duì)象
        element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector("div.dv_handler.dv_handler_bg"));
        // 按下滑塊
        actions.clickAndHold(element).perform();
        Iterator it = moveTrace.iterator();
        while (it.hasNext()) {
            // 位移一次
            int dis = (int) it.next();
            moveWithoutWait(dis, 0);
        }
        // 模擬人的操作,超過(guò)區(qū)域
        moveWithoutWait(5, 0);
        moveWithoutWait(-3, 0);
        moveWithoutWait(-2, 0);
        // 釋放滑塊
        actions.release().perform();
        Thread.sleep(500);
    }

    /**
     * 消除selenium中移動(dòng)操作的卡頓感
     * 這種卡頓感是因?yàn)閟elenium中自帶的moveByOffset是默認(rèn)有200ms的延時(shí)的
     * 可參考:https://blog.csdn.net/fx9590/article/details/113096513
     *
     * @param x x軸方向位移距離
     * @param y y軸方向位移距離
     */
    public void moveWithoutWait(int x, int y) {
        PointerInput defaultMouse = new PointerInput(MOUSE, "default mouse");
        actions.tick(defaultMouse.createPointerMove(Duration.ofMillis(5), PointerInput.Origin.pointer(), x, y)).perform();
    }

為了防止每天頻繁登錄,可能會(huì)被封號(hào)。 我們還要實(shí)現(xiàn)每天只需要登錄一次,其余時(shí)間都是免登錄

// 每天重新登陸一次
File cookieFile = new File("example.cookie.txt" + DateUtil.today());
if (!cookieFile.exists()) {
    // 文件不存在則認(rèn)為是當(dāng)天首次登錄,清空緩存文件
    FileUtil.del(tempDirect);
}
/**
 * 保存cookie
 * @throws IOException
 */
private void saveCookie() throws IOException {
    File cookieFile = new File("example.cookie.txt" + DateUtil.today());
    cookieFile.delete();
    cookieFile.createNewFile();
    FileWriter fileWriter = new FileWriter(cookieFile);
    BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

    for (Cookie cookie : driver.manage().getCookies()) {
        bufferedWriter.write((cookie.getName() + ";" +
                cookie.getValue() + ";" +
                cookie.getDomain() + ";" +
                cookie.getPath() + ";" +
                cookie.getExpiry() + ";" +
                cookie.isSecure()));
        bufferedWriter.newLine();
    }
    bufferedWriter.flush();
    bufferedWriter.close();
    fileWriter.close();
}
/**
 * 讀取cookie加載到瀏覽器
 * @throws IOException
 */
private void addCookie() throws IOException {
    File cookieFile = new File("example.cookie.txt" + DateUtil.today());
    if (cookieFile.exists()) {
        FileReader fileReader = new FileReader(cookieFile);
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        String line;

        while ((line = bufferedReader.readLine()) != null) {
            StringTokenizer stringTokenizer = new StringTokenizer(line, ";");
            while (stringTokenizer.hasMoreTokens()) {

                String name = stringTokenizer.nextToken();
                String value = stringTokenizer.nextToken();
                String domain = stringTokenizer.nextToken();
                String path = stringTokenizer.nextToken();
                Date expiry = null;
                String dt;

                if (!(dt = stringTokenizer.nextToken()).equals("null")) {
                    expiry = new Date(dt);
                }

                boolean isSecure = new Boolean(stringTokenizer.nextToken()).booleanValue();
                Cookie cookie = new Cookie(name, value, domain, path, expiry, isSecure);
                driver.manage().addCookie(cookie);
            }
        }
    }
}

完整代碼

package com.fandf.selenium;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fandf.email.EmailService;
import com.fandf.utils.SeleniumUtil;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.PointerInput;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.time.Duration;
import java.util.List;
import java.util.*;

import static org.openqa.selenium.interactions.PointerInput.Kind.MOUSE;

/**
 * @author fandongfeng
 * @date 2023-12-10 13:48
 **/
@Slf4j
public class SliderAutomatic implements Closeable {

    private WebDriver driver;

    private Actions actions;

    private WebElement element;

    private JavascriptExecutor js;

    // 帶有缺口的驗(yàn)證碼
    private BufferedImage notchPicture;

    // 不帶有缺口的驗(yàn)證碼
    private BufferedImage fullPicture;

    // chromedriver地址
    private final static String chromedriver = "C:\Users\Administrator\Desktop\chrome\chromedriver.exe";
    // 瀏覽器緩存地址
    private final static String tempDirect = "C:\Users\Administrator\Desktop\chrome\temp";

    @Override
    public void close() {
        if (driver != null) {
            driver.quit();
        }
    }

    public String login() throws Exception {
        log.info("開(kāi)始登錄");
        System.setProperty("webdriver.chrome.driver", chromedriver);

        // 每天重新登陸一次
        File cookieFile = new File("example.cookie.txt" + DateUtil.today());
        if (!cookieFile.exists()) {
            // 文件不存在則認(rèn)為是當(dāng)天首次登錄,清空緩存文件
            FileUtil.del(tempDirect);
        }


        log.info("清除緩存成功");
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--remote-allow-origins=*");
        String userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";
        options.addArguments("--user-agent=" + userAgent);
        options.addArguments("--disable-gpu");
        options.addArguments("--disable-dev-shm-usage");
        options.addArguments("--no-sandbox");
        options.addArguments("--single-process");
        options.addArguments("--disable-setuid-sandbox");
        // 啟用自動(dòng)化擴(kuò)展
        options.setExperimentalOption("excludeSwitches", Arrays.asList("enable-automation"));
        options.addArguments("--disable-blink-features=AutomationControlled");
        // 禁用瀏覽器的安全性
        options.addArguments("--disable-web-security");
        options.addArguments("--allow-running-insecure-content");
        //禁用瀏覽器的同源策略
        options.addArguments("--disable-features=IsolateOrigins,site-per-process");

        options.addArguments("--user-data-dir=" + tempDirect);
        // 設(shè)置后臺(tái)靜默模式啟動(dòng)瀏覽器
//        options.addArguments("--headless=new");


        log.info("設(shè)置請(qǐng)求頭完成");
        driver = new ChromeDriver(options);

        driver.manage().window().maximize();
        js = (JavascriptExecutor) driver;
        js.executeScript("window.scrollTo(1,100)");
        actions = new Actions(driver);
        // 先訪問(wèn)在在加載cookie 否則報(bào)錯(cuò) invalid cookie domain
        driver.get("www.example.com");
        // 讀取cookie加載到瀏覽器
        addCookie();
        // 刷新頁(yè)面
        driver.navigate().refresh();
        if (!isLogin()) {
            log.info("開(kāi)始登錄...");
            // 登錄
            loginExample();
            // 登錄成功后先刷新
            driver.navigate().refresh();
        } else {
            log.info("免登錄成功...");
        }


        String token = null;

        Set<Cookie> cookies = driver.manage().getCookies();
        for (Cookie cookie : cookies) {
            log.info("cookie= {}", JSONUtil.toJsonStr(cookie));
            if (cookie.getName().equals("Example-Token")) {
                // 登錄成功后會(huì)返回token
                log.info("Example-Token 的值為:" + cookie.getValue());
                token = cookie.getValue();
            }
        }

        // token存在則證明登錄成功
        if (StrUtil.isNotBlank(token)) {
            saveCookie();
        }

        return token;
    }

    /**
     * 讀取cookie加載到瀏覽器
     *
     * @throws IOException
     */
    private void addCookie() throws IOException {
        File cookieFile = new File("example.cookie.txt" + DateUtil.today());
        if (cookieFile.exists()) {
            FileReader fileReader = new FileReader(cookieFile);
            BufferedReader bufferedReader = new BufferedReader(fileReader);

            String line;

            while ((line = bufferedReader.readLine()) != null) {
                StringTokenizer stringTokenizer = new StringTokenizer(line, ";");
                while (stringTokenizer.hasMoreTokens()) {

                    String name = stringTokenizer.nextToken();
                    String value = stringTokenizer.nextToken();
                    String domain = stringTokenizer.nextToken();
                    String path = stringTokenizer.nextToken();
                    Date expiry = null;
                    String dt;

                    if (!(dt = stringTokenizer.nextToken()).equals("null")) {
                        expiry = new Date(dt);
                    }

                    boolean isSecure = new Boolean(stringTokenizer.nextToken()).booleanValue();
                    Cookie cookie = new Cookie(name, value, domain, path, expiry, isSecure);
                    driver.manage().addCookie(cookie);
                }
            }
        }
    }

    /**
     * 保存cookie
     *
     * @throws IOException
     */
    private void saveCookie() throws IOException {
        File cookieFile = new File("example.cookie.txt" + DateUtil.today());
        cookieFile.delete();
        cookieFile.createNewFile();
        FileWriter fileWriter = new FileWriter(cookieFile);
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

        for (Cookie cookie : driver.manage().getCookies()) {
            bufferedWriter.write((cookie.getName() + ";" +
                    cookie.getValue() + ";" +
                    cookie.getDomain() + ";" +
                    cookie.getPath() + ";" +
                    cookie.getExpiry() + ";" +
                    cookie.isSecure()));
            bufferedWriter.newLine();
        }
        bufferedWriter.flush();
        bufferedWriter.close();
        fileWriter.close();
    }

    private void loginExample() throws Exception {
        js.executeScript("window.scrollTo(1,100)");
        // 調(diào)出驗(yàn)證碼
        WebElement element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector("div.login"));
        element.click();
        element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector("input[name='username']"));
        element.clear();
        element.sendKeys("123456789@163.com");
        log.info("開(kāi)始登錄郵箱123456789@163.com");

        element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector(".SendCode.correct"));
        element.click();
        log.info("點(diǎn)擊登錄發(fā)送郵件完成");
        // 等待驗(yàn)證碼出現(xiàn)
        SeleniumUtil.waitMostSeconds(driver, By.cssSelector(".drag-verify-container.veriftyItem"));
        // 等待5秒,網(wǎng)絡(luò)問(wèn)題,等待圖片顯示出來(lái)
        log.info("等待5秒,網(wǎng)絡(luò)問(wèn)題,等待圖片顯示出來(lái)");
        Thread.sleep(5000);

        // 保存驗(yàn)證碼
        saveCode();
        int position = comparePicture();
        log.info("滑塊位置:{}", position);
        move(Collections.singletonList(position));
        log.info("移動(dòng)滑塊位置成功,開(kāi)始等待驗(yàn)證碼");
        // 等待10秒,收到郵件
        Thread.sleep(20000);
        // 輸入郵箱驗(yàn)證碼
        String emailLoginCode = EmailService.getLoginCode();
        element = SeleniumUtil.waitMostSeconds(driver, By.xpath("http://*[@id="app"]/div[1]/div/form/div[2]/div[2]/input"));
        element.clear();
        element.sendKeys(emailLoginCode);
        log.info("郵箱驗(yàn)證碼為:{}", emailLoginCode);
        // 點(diǎn)擊登錄
        element = SeleniumUtil.waitMostSeconds(driver, By.xpath("http://*[@id="app"]/div[1]/div/form/div[3]/div/button"));
        element.click();
        log.info("登陸成功了");
    }

    /**
     * 移動(dòng)滑塊,實(shí)現(xiàn)驗(yàn)證
     *
     * @param moveTrace 滑塊的運(yùn)動(dòng)軌跡
     * @throws Exception
     */
    private void move(List<Integer> moveTrace) throws Exception {
        // 獲取滑塊對(duì)象
        element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector("div.dv_handler.dv_handler_bg"));
        // 按下滑塊
        actions.clickAndHold(element).perform();
        Iterator it = moveTrace.iterator();
        while (it.hasNext()) {
            // 位移一次
            int dis = (int) it.next();
            moveWithoutWait(dis, 0);
        }
        // 模擬人的操作,超過(guò)區(qū)域
        moveWithoutWait(5, 0);
        moveWithoutWait(-3, 0);
        moveWithoutWait(-2, 0);
        // 釋放滑塊
        actions.release().perform();
        Thread.sleep(500);
    }

    /**
     * 消除selenium中移動(dòng)操作的卡頓感
     * 這種卡頓感是因?yàn)閟elenium中自帶的moveByOffset是默認(rèn)有200ms的延時(shí)的
     * 可參考:https://blog.csdn.net/fx9590/article/details/113096513
     *
     * @param x x軸方向位移距離
     * @param y y軸方向位移距離
     */
    private void moveWithoutWait(int x, int y) {
        PointerInput defaultMouse = new PointerInput(MOUSE, "default mouse");
        actions.tick(defaultMouse.createPointerMove(Duration.ofMillis(5), PointerInput.Origin.pointer(), x, y)).perform();
    }

    /**
     * 比較兩張截圖,找出有缺口的驗(yàn)證碼截圖中缺口所在位置
     * 由于滑塊是x軸方向位移,因此只需要x軸的坐標(biāo)即可
     *
     * @return 缺口起始點(diǎn)x坐標(biāo)
     * @throws Exception
     */
    private int comparePicture() throws Exception {
        notchPicture = ImageIO.read(new File("有缺口.png"));
        fullPicture = ImageIO.read(new File("無(wú)缺口.png"));
        int width = notchPicture.getWidth();
        int height = notchPicture.getHeight();
        int pos = 70;  // 小方塊的固定起始位置
        // 橫向掃描
        for (int i = pos; i < width; i++) {
            for (int j = 0; j < height - 10; j++) {
                if (!equalPixel(i, j)) {
                    pos = i;
                    return pos;
                }
            }
        }
        throw new Exception("未找到滑塊缺口");
    }

    /**
     * 比較兩張截圖上的當(dāng)前像素點(diǎn)的RGB值是否相同
     * 只要滿足一定誤差閾值,便可認(rèn)為這兩個(gè)像素點(diǎn)是相同的
     *
     * @param x 像素點(diǎn)的x坐標(biāo)
     * @param y 像素點(diǎn)的y坐標(biāo)
     * @return true/false
     */
    private boolean equalPixel(int x, int y) {
        int rgbaBefore = notchPicture.getRGB(x, y);
        int rgbaAfter = fullPicture.getRGB(x, y);
        // 轉(zhuǎn)化成RGB集合
        Color colBefore = new Color(rgbaBefore, true);
        Color colAfter = new Color(rgbaAfter, true);
        int threshold = 220;   // RGB差值閾值
        if (Math.abs(colBefore.getRed() - colAfter.getRed()) < threshold &&
                Math.abs(colBefore.getGreen() - colAfter.getGreen()) < threshold &&
                Math.abs(colBefore.getBlue() - colAfter.getBlue()) < threshold) {
            return true;
        }
        return false;
    }

    /**
     * 獲取無(wú)缺口的驗(yàn)證碼和帶有缺口的驗(yàn)證碼
     */
    private void saveCode() {
     
        // 隱藏缺口
        // 隱藏滑塊
        js.executeScript("document.querySelectorAll('canvas')[0].style='display'");
        js.executeScript("document.querySelectorAll('canvas')[1].hidden='true'");
        WebElement element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector("canvas.main-canvas"));
        File screen = element.getScreenshotAs(OutputType.FILE); //執(zhí)行屏幕截取
        SeleniumUtil.savePng(screen, "無(wú)缺口");
        log.info("保存無(wú)缺口的截圖完成");

        // 獲取有缺口的截圖
        // 隱藏滑塊
        js.executeScript("document.querySelectorAll('canvas')[1].style='display'");
        js.executeScript("document.querySelectorAll('canvas')[1].hidden='true'");
        WebElement element = SeleniumUtil.waitMostSeconds(driver, By.cssSelector("canvas.main-canvas"));
        File screen = element.getScreenshotAs(OutputType.FILE); //執(zhí)行屏幕截取
        SeleniumUtil.savePng(screen, "有缺口");
        // 展示滑塊
        js.executeScript("document.querySelectorAll('canvas')[1].style='display: block;'");
        log.info("保存有缺口的截圖完成");
    }

    /**
     * 通過(guò)頁(yè)面是否有l(wèi)ogin按鈕來(lái)判斷是否登錄
     * T 登錄了,  F 未登錄
     */
    private boolean isLogin() {
        return !SeleniumUtil.containElement(driver, By.cssSelector("div.login"));
    }


}
package com.fandf.utils;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.io.IOException;
import java.time.Duration;

/**
 * @author fandongfeng
 * @date 2023/12/9 18:29
 */
public class SeleniumUtil {

    /**
     * 判斷元素是否存在
     *
     * @param driver 驅(qū)動(dòng)
     * @param by     元素定位方式
     * @return 元素控件
     */
    public static boolean containElement(WebDriver driver, By by) {
        try {
            WebDriverWait AppiumDriverWait = new WebDriverWait(driver, Duration.ofSeconds(5));
            AppiumDriverWait.until(ExpectedConditions
                    .presenceOfElementLocated(by));
            return true;
        } catch (Exception ignore) {
        }
        return false;
    }

    /**
     * Selenium方法等待元素出現(xiàn)
     *
     * @param driver 驅(qū)動(dòng)
     * @param by     元素定位方式
     * @return 元素控件
     */
    public static WebElement waitMostSeconds(WebDriver driver, By by) {
        try {
            WebDriverWait AppiumDriverWait = new WebDriverWait(driver, Duration.ofSeconds(5));
            return (WebElement) AppiumDriverWait.until(ExpectedConditions
                    .presenceOfElementLocated(by));
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new NoSuchElementException("元素控件未出現(xiàn)");
    }

    /**
     * 保存截圖的方法
     *
     * @param screen 元素截圖
     * @param name   截圖保存名字
     */
    public static void savePng(File screen, String name) {
        String screenShortName = name + ".png";
        try {
            System.out.println("save screenshot");
            FileUtils.copyFile(screen, new File(screenShortName));
        } catch (IOException e) {
            System.out.println("save screenshot fail");
            e.printStackTrace();
        } finally {
            System.out.println("save screenshot finish");
        }
    }

}

到此這篇關(guān)于java+selenium實(shí)現(xiàn)滑塊驗(yàn)證的文章就介紹到這了,更多相關(guān)java selenium滑塊驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JDK自帶的jstat命令該怎么用詳解

    JDK自帶的jstat命令該怎么用詳解

    jstat是jdk的命令(查看jvm的統(tǒng)計(jì)信息),可以監(jiān)控類似類加載信息,GC信息等,這篇文章主要介紹了JDK自帶的jstat命令該怎么用的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-10-10
  • Spring Cloud Stream分區(qū)分組原理圖解

    Spring Cloud Stream分區(qū)分組原理圖解

    這篇文章主要介紹了Spring Cloud Stream的分區(qū)和分組,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Redis緩存策略超詳細(xì)講解

    Redis緩存策略超詳細(xì)講解

    實(shí)際開(kāi)發(fā)中緩存處理是必須的,不可能我們每次客戶端去請(qǐng)求一次服務(wù)器,服務(wù)器每次都要去數(shù)據(jù)庫(kù)中進(jìn)行查找,為什么要使用緩存?說(shuō)到底是為了提高系統(tǒng)的運(yùn)行速度
    2022-09-09
  • Java實(shí)現(xiàn)Excel與TXT文本的高效互轉(zhuǎn)

    Java實(shí)現(xiàn)Excel與TXT文本的高效互轉(zhuǎn)

    在日常開(kāi)發(fā)中,我們經(jīng)常需要在不同的數(shù)據(jù)存儲(chǔ)格式之間進(jìn)行轉(zhuǎn)換,本文將分享如何在 Java 中高效實(shí)現(xiàn) Excel 與 TXT 的互轉(zhuǎn),有需要的小伙伴可以了解下
    2025-09-09
  • SpringBoot中的自定義FailureAnalyzer詳解

    SpringBoot中的自定義FailureAnalyzer詳解

    這篇文章主要介紹了SpringBoot中的自定義FailureAnalyzer詳解,FailureAnalyzer是一種很好的方式在啟動(dòng)時(shí)攔截異常并將其轉(zhuǎn)換為易讀的消息,并將其包含在FailureAnalysis中, Spring Boot為應(yīng)用程序上下文相關(guān)異常、JSR-303驗(yàn)證等提供了此類分析器,需要的朋友可以參考下
    2023-12-12
  • SpringBoot實(shí)現(xiàn)數(shù)據(jù)預(yù)熱的方式小結(jié)

    SpringBoot實(shí)現(xiàn)數(shù)據(jù)預(yù)熱的方式小結(jié)

    這里用到的數(shù)據(jù)預(yù)熱,就是在項(xiàng)目啟動(dòng)時(shí)將一些數(shù)據(jù)量較大的數(shù)據(jù)加載到緩存中(筆者這里用的Redis),那么在項(xiàng)目啟動(dòng)有哪些方式可以實(shí)現(xiàn)數(shù)據(jù)預(yù)熱呢,本文就來(lái)給大家講講幾種實(shí)現(xiàn)數(shù)據(jù)預(yù)熱的方式,需要的朋友可以參考下
    2023-09-09
  • Spring Xml裝配Bean的思路詳解

    Spring Xml裝配Bean的思路詳解

    在Spring中提供了三種方式來(lái)對(duì)Bean進(jìn)行配置,本文針對(duì)每種方式給大家介紹的非常詳細(xì),對(duì)Spring Xml裝配Bean的思路相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-10-10
  • Java訪問(wèn)Hadoop分布式文件系統(tǒng)HDFS的配置說(shuō)明

    Java訪問(wèn)Hadoop分布式文件系統(tǒng)HDFS的配置說(shuō)明

    Hadoop的能提供高吞吐量的數(shù)據(jù)訪問(wèn),是集群式服務(wù)器的上的數(shù)據(jù)操作利器,這里就來(lái)為大家分享Java訪問(wèn)Hadoop分布式文件系統(tǒng)HDFS的配置說(shuō)明:
    2016-06-06
  • JavaAgent的簡(jiǎn)單例子

    JavaAgent的簡(jiǎn)單例子

    這篇文章主要介紹了JavaAgent的簡(jiǎn)單例子,對(duì)JavaAgent感興趣的同學(xué),可以參考下
    2021-04-04
  • JAVA CountDownLatch(倒計(jì)時(shí)計(jì)數(shù)器)用法實(shí)例

    JAVA CountDownLatch(倒計(jì)時(shí)計(jì)數(shù)器)用法實(shí)例

    這篇文章主要介紹了JAVA CountDownLatch(倒計(jì)時(shí)計(jì)數(shù)器)用法實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10

最新評(píng)論

赣州市| 文昌市| 东安县| 太仆寺旗| 东明县| 兴安县| 泰安市| 民县| 武安市| 华亭县| 清徐县| 漳浦县| 乌兰察布市| 绥江县| 通河县| 赤水市| 乌兰察布市| 繁昌县| 商南县| 樟树市| 乌鲁木齐市| 澳门| 鲁山县| 石狮市| 蒲城县| 西青区| 寻乌县| 阿拉善右旗| 延津县| 化州市| 马公市| 得荣县| 黄冈市| 嵩明县| 天等县| 泸州市| 临沭县| 普兰县| 广安市| 中方县| 思茅市|