【教程】JAVA + selenium 进行自动化测试

【教程】JAVA + selenium 进行自动化测试

自动登录淘宝

获取请求响应数据等

package com.guanwei.study.抓包.selenium;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.UnexpectedAlertBehaviour;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.devtools.Command;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v109.network.Network;
import org.openqa.selenium.devtools.v109.network.model.Request;
import org.openqa.selenium.devtools.v109.network.model.RequestId;
import org.openqa.selenium.devtools.v109.network.model.ResourceType;
import org.openqa.selenium.devtools.v109.network.model.Response;
import org.openqa.selenium.interactions.Actions;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 官方API
 * https://www.selenium.dev/documentation/webdriver/bidirectional/
 */
@Slf4j
public class Demo {

    /**
     * 是否开启无头浏览器模式(不打开浏览器界面看不到界面 速度更快)
     * linux服务器 需要用true
     * 声明一个ChromeOptions变量,并配置headless属性为true,表示不在前台打开chrome。
     */
    public static boolean headless = false;

    /**
     * 是否禁用图片
     */
    public static boolean imagesEnabled = false;

    /**
     * chromedirver存放位置
     */
    public static String chromedirverPath = "C:\\Users\\TC_em\\AppData\\Local\\Google\\Chrome\\Application\\chromedriver.exe";
    

    public static void main(String[] args) {


        // 设置 chromedirver的存放位置
        System.getProperties().setProperty("webdriver.chrome.driver", chromedirverPath);

//        ImmutableMap.of(
//                "", new CommandInfo("session/:sessionId/goog/cast/get_sinks", HttpMethod.GET),
//                "", new CommandInfo("session/:sessionId/goog/cast/set_sink_to_use", HttpMethod.POST),
//                "", new CommandInfo("session/:sessionId/goog/cast/start_desktop_mirroring", HttpMethod.POST),
//                "", new CommandInfo("session/:sessionId/goog/cast/start_tab_mirroring", HttpMethod.POST),
//                "", new CommandInfo("session/:sessionId/goog/cast/get_issue_message", HttpMethod.GET),
//                "", new CommandInfo("session/:sessionId/goog/cast/stop_casting", HttpMethod.POST));


        // 设置浏览器参数
        ChromeOptions chromeOptions = new ChromeOptions();

        //是否开启无头浏览模式
        chromeOptions.setHeadless(headless);
        chromeOptions.getCapabilityNames();

        //设置为 headless 模式避免报错用的参数
        chromeOptions.addArguments("--disable-gpu");

        //禁用沙箱
        chromeOptions.addArguments("--no-sandbox");

        //禁用开发者shm
        chromeOptions.addArguments("--disable-dev-shm-usage");

        chromeOptions.setPageLoadStrategy(PageLoadStrategy.NORMAL);

        //文档地址:https://www.selenium.dev/zh-cn/documentation/webdriver/capabilities/shared/#unhandledpromptbehavior
        chromeOptions.setUnhandledPromptBehaviour(UnexpectedAlertBehaviour.IGNORE);

        //传下面参数来禁止掉谷歌受自动化控制的信息栏
        chromeOptions.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
        if (!headless) {//有界面时给予跳过弹窗的处理
            Object prefs = SeleniumUtil.getAllowProtocolPrefs();
            //Object prefs = getExcludedProtocolPrefs();
            //Object prefs = getCustomProtocolPrefs();
            chromeOptions.setExperimentalOption("prefs", prefs);
        }


        // 禁用阻止弹出窗口
//        chromeOptions.addArguments("--disable-popup-blocking")
        
        
        // 禁用保存密码提示框
        Map prefs = new HashMap();
        prefs.put("credentials_enable_service", false);
        prefs.put("profile.password_manager_enabled", false);
        chromeOptions.setExperimentalOption("prefs", prefs);

        if(imagesEnabled){

            //禁用图片
            chromeOptions.addArguments("blink-settings=imagesEnabled=false");
        }
        
        
        //更换代理ip
        /**
         * proxy_arr = [
         *     '--proxy-server=http://111.3.118.247:30001',
         *     '--proxy-server=http://183.247.211.50:30001',
         *     '--proxy-server=http://122.9.101.6:8888',
         * ]
         */
//        chromeOptions.addArguments("--proxy-server=http://111.3.118.247:30001");
        
        
        
        /**
         * 反反爬虫 Start
         */

        chromeOptions.addArguments("--disable-blink-features");
        chromeOptions.addArguments("--disable-blink-features=AutomationControlled");

        /**
         * 反反爬虫 End
         */


        //初始化
        ChromeDriver driver = new ChromeDriver(chromeOptions);   //初始化一个chrome驱动实例,保存到driver中
        // WebDriver driver =  = new FirefoxDriver();  	



//        NetworkInterceptor interceptor = new NetworkInterceptor(
//                driver,
//                Route.matching(req -> true)
//                        .to(() -> req -> new HttpResponse()
//                                .setStatus(200)
//                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
//                        
//                        )
//                
//                
//        );


        //方法三:字节数组
//        InputStream inputStreamRoute = new ByteArrayInputStream(
//                new String("你好啊").getBytes());
//        
//        NetworkInterceptor interceptor = new NetworkInterceptor(
//                driver,
//                new Route() {
//                    @Override
//                    protected HttpResponse handle(HttpRequest req) {
//                        return new HttpResponse().setStatus(200).setContent(new Supplier() {
//                            @Override
//                            public InputStream get() {
//                                return inputStreamRoute;
//                            }
//                        });
//                    }
//
//                    @Override
//                    public boolean matches(HttpRequest req) {
//                        return true;
//                    }
//                }
//        );


//        AddSeleniumUserAgent addSeleniumUserAgent = new AddSeleniumUserAgent();
//
//        addSeleniumUserAgent.
//        
//        NetworkInterceptor interceptor = new NetworkInterceptor(
//                driver,
//                new 
//        );
        
        
        
        
        /**
         * 监听网络
         * https://blog.51cto.com/u_15406013/4331846
         * 操作网络请求
         * https://www.selenium.dev/documentation/webdriver/bidirectional/bidi_api_remotewebdriver/
         * 
         * 
         * 
         */
        DevTools devTools = driver.getDevTools();

        devTools.createSession();
        devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

        devTools.addListener(Network.requestIntercepted(), responseReceived -> {

            Request request = responseReceived.getRequest();
            String url = request.getUrl();


        });

        devTools.addListener(Network.requestServedFromCache(), responseReceived -> {
            String s = responseReceived.toJson();

            System.out.println(s);

        });

        /**
         * 获取Request信息
         * 监听将被发送的数据
         */
        devTools.addListener(Network.requestWillBeSent(), responseReceived -> {

            Request request = responseReceived.getRequest();

            String method = request.getMethod();

            Optional resourceType = responseReceived.getType();

            String type = resourceType.get().toJson();
            String url = request.getUrl();

            switch (type){
                case "Document":
                case "Image":
                case "Font":
                case "Ping":
                case "Script":
                case "Stylesheet":
                case "Fetch":
                    return;

                case "Other":

                    if(url.endsWith(".ico")
                            || url.endsWith(".png")
                            || url.endsWith(".jpg")
                            || url.endsWith(".gif")
                    ){
                        return;
                    }



                case "XHR":

                default:
                    break;
            }
            
            if(url.contains(".js")
            || url.contains(".css")
            || url.contains(".jpg")
            || url.contains(".png")
            || url.contains(".gif")
            ){
                return;
            }

            System.out.println(url);

            if(url.equalsIgnoreCase("https://login.taobao.com/newlogin/login.do?appName=taobao&fromSite=0&_bx-v=2.2.3")){
                request.getPostData().map(new Function() {
                    @Override
                    public Object apply(String s) {
                        return null;
                    }
                });
            }
            
            System.out.println(request);

        });
        
        
        /**
         * 获取Response信息
         * 监听网络请求返回值  这里可以抓包
         * 
         * devTools是通过事件监听来获取网络数据的,具体监听事件有很多,比如responseReceived,requestWillBeSent,dataReceived等等。
         *
         * 需要注意的有几点:
         *
         * 获取response的时候,记得try catch,以防止有的请求并没有body导致的异常。
         * responseReceived事件触发时,这个时候获取response未必能取到,因为只是响应返回了,但是body可能比较大,数据可能还没有接收完。
         * dataReceived事件触发时,大概率是可以获取到返回的body的,但是保险起见,可以sleep500毫秒。
         * 如果有一些请求,请求的URL都一样,只是参数不同,而我们只关心特定参数的request返回的response,则可以订阅requestWillBeSent事件,确认该请求是需要的,则把RequestId扔到队列里,在dataReceived的时候从队列里取出RequestId来获取返回数据。
         * requestWillBeSent的RequestId和dataReceived的RequestId内容是一样的。
         * 除了通过devTools监听数据外,还可以做很多其它的事情,比如修改请求HEAD,修改Cookie,具体API可以去​ ​官网​​查询。
         *
         * 当然有了driver一样可以像以前一样,访问URL,获取页面元素,交互。比如如下代码
         * -----------------------------------
         * ©著作权归作者所有:来自51CTO博客作者武码公社的原创作品,请联系作者获取转载授权,否则将追究法律责任
         * 使用selenium4监听网络请求
         * https://blog.51cto.com/u_15406013/4331846
         */
        devTools.addListener(Network.responseReceived(), responseReceived -> {
            RequestId requestId = responseReceived.getRequestId();
            Response receivedResponse = responseReceived.getResponse();
            String url = receivedResponse.getUrl();
            String type = responseReceived.getType().toString();
            
            switch (type){
                case "Document":
                case "Image":
                case "Font":
                case "Ping":
                case "Script":
                case "Stylesheet":
                case "Fetch":
                    return;

                case "Other":
                    
                    if(url.endsWith(".ico")
                    || url.endsWith(".png")
                    || url.endsWith(".jpg")
                    || url.endsWith(".gif")
                    ){
                        return;
                    }
                case "XHR":
                
                default:
                    break;
            }
            
            System.out.println("type:" + type + ", url:" + url);

            //进行请求
            try {

                Command requestPostData = Network.getRequestPostData(requestId);

                //请求参数
                Command responseBody = Network.getResponseBody(requestId);
                
                //类型
                String method = responseBody.getMethod();
                //参数
                Map params = responseBody.getParams();


                Command responseBody1 = responseBody;
                Map params1 = responseBody1.getParams();

                //执行请求
                Network.GetResponseBodyResponse response = devTools.send(responseBody1);
                
                //是否base64编码
                Boolean base64Encoded = response.getBase64Encoded();
                
                //获取body
                String body = response.getBody();
                
                if(base64Encoded){
                    //进行解码
                    body = Base64.decodeStr(body);
                }
                

                log.debug(body);
            }catch (Exception e){
                log.error(e.getMessage(), e);
            }
            
            
        });

        //清理cooki
//        driver.manage().deleteAllCookies();

        // 与浏览器同步非常重要,必须等待浏览器加载完毕
        //隐式等待10秒
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        //最大化窗口
        driver.manage().window().maximize();  //最大化窗口
        //设置隐性等待时间

        driver.get("https://www.taobao.com/");
        ThreadUtil.sleep(2000);  //等待页面加载完成,后续写代码注意,如果页面加载未完成,可能导致页面元素找不到
        System.out.println("当前打开页面的标题是: "+ driver.getTitle());

        //判断是否登陆
        // 选择元素并进行点击
        driver.findElement(By.linkText("亲,请登录")).click();

        ThreadUtil.sleep(2000);  //等待页面加载完成,后续写代码注意,如果页面加载未完成,可能导致页面元素找不到
        System.out.println("当前打开页面的标题是: "+ driver.getTitle());
        
        //输入账号密码
        driver.findElement(By.id("fm-login-id")).sendKeys("淘宝账号");
        driver.findElement(By.id("fm-login-password")).sendKeys("淘宝密码");
        ThreadUtil.sleep(2000);
        
        //滑块  nc_1_n1z
        ;

        //拖拽
        Actions action = new Actions(driver);
        // 鼠标拖拽动作,将 source 元素拖放到 target 元素的位置。
//        action.dragAndDrop(driver.findElement(By.id("nc_1_n1z")),driver.findElement(By.id("nc_1__scale_text")));
        // 鼠标拖拽动作,将 source 元素拖放到 (xOffset, yOffset) 位置,其中 xOffset 为横坐标,yOffset 为纵坐标。

        
//        action.dragAndDrop(driver.findElement(By.id("nc_1_n1z")),xOffset,yOffset);
        
        //移动到对应的偏移量
        action.dragAndDropBy(driver.findElement(By.id("nc_1_n1z")),-260,0);
        ThreadUtil.sleep(2000);
//        action.dragAndDropBy()

        //点击登陆按钮
        driver.findElement(By.cssSelector(".fm-btn button")).click();





        ThreadUtil.sleep(100 * 1000);

        //关闭并退出浏览器
        driver.quit();

        
    }
    
    
}

使用到的工具类

package com.guanwei.study.抓包.selenium;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Wait;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 参考
 * https://blog.csdn.net/qq_26819733/article/details/126799304
 */
public class SeleniumUtil {



    public static void handlerAlert(ChromeDriver driver) {
        //        Wait wait = new FluentWait(driver)
//                .withTimeout(Duration.ofSeconds(30))
//                .pollingEvery(Duration.ofSeconds(5));
        Wait wait = new WebDriverWait(driver, Duration.ofMillis(1l));
        try {
            wait.until(ExpectedConditions.alertIsPresent());
            Alert alert = driver.switchTo().alert();
            alert.dismiss();
        } catch (Exception e) {
        }
    }

    public static Object getCustomProtocolPrefs() {
        Map ignoredProtocolHandlers = new HashMap<>();
        ignoredProtocolHandlers.put("protocol", "macappstores");
        Map customHandlers = new HashMap<>();
        customHandlers.put("ignored_protocol_handlers", Arrays.asList(ignoredProtocolHandlers));
        customHandlers.put("enabled", true);
        Map prefs = new HashMap<>();
        prefs.put("custom_handlers", customHandlers);
        return prefs;
    }

    public static Object getExcludedProtocolPrefs() {
        Map excludedSchemes = new HashMap<>();
        excludedSchemes.put("macappstores", true);
        Map protocolHandler = new HashMap<>();
        protocolHandler.put("excluded_schemes", excludedSchemes);
        Map prefs = new HashMap<>();
        prefs.put("protocol_handler", protocolHandler);
        return prefs;
    }
    

    public static Object getAllowProtocolPrefs() {
        Map appleUrl = new HashMap<>();
        appleUrl.put("macappstores", true);
        Map allowedOriginProtocolPairs = new HashMap<>();
        allowedOriginProtocolPairs.put("https://apps.apple.com", appleUrl);
        Map protocolHandler = new HashMap<>();
        protocolHandler.put("allowed_origin_protocol_pairs", allowedOriginProtocolPairs);
        Map prefs = new HashMap<>();
        prefs.put("protocol_handler", protocolHandler);
        return prefs;
    }


    /**
     * 点击按钮 如果不存在则等待
     * @param driver
     * @param elementId
     * @param name
     */
    protected void clickConfirmWindow(WebDriver driver, By by, String name) {
        // Check if warning window is displayed using button ID
        System.out.println("Searching " + name + " using " + by);
        if (isClickable(driver, by, 1)) {
            System.out.println("Found " + name + " using " + by);
            driver.findElement(by).click();
        }
    }


    /**
     * 检查元素是否存在 等待
     * @param driver
     * @param by
     * @param timeOut
     * @return
     */
    private Boolean isClickable(WebDriver driver, By by, int timeOut) {
        try {
            new WebDriverWait(driver, Duration.ofMillis(timeOut)).until(ExpectedConditions.visibilityOfElementLocated(by));
            return true;
        } catch (TimeoutException e) {
            e.printStackTrace();
            return false;
        }
    }
    
    
    
    
}

你可能感兴趣的:(使用说明,chrome,python,前端)