【教程】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<String, Object> 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<InputStream>() {
// @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> 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<String, Object>() {
@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<String> requestPostData = Network.getRequestPostData(requestId);
//请求参数
Command<Network.GetResponseBodyResponse> responseBody = Network.getResponseBody(requestId);
//类型
String method = responseBody.getMethod();
//参数
Map<String, Object> params = responseBody.getParams();
Command<Network.GetResponseBodyResponse> responseBody1 = responseBody;
Map<String, Object> 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<WebDriver> wait = new FluentWait<WebDriver>(driver)
// .withTimeout(Duration.ofSeconds(30))
// .pollingEvery(Duration.ofSeconds(5));
Wait<WebDriver> 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<String, Object> ignoredProtocolHandlers = new HashMap<>();
ignoredProtocolHandlers.put("protocol", "macappstores");
Map<String, Object> customHandlers = new HashMap<>();
customHandlers.put("ignored_protocol_handlers", Arrays.asList(ignoredProtocolHandlers));
customHandlers.put("enabled", true);
Map<String, Object> prefs = new HashMap<>();
prefs.put("custom_handlers", customHandlers);
return prefs;
}
public static Object getExcludedProtocolPrefs() {
Map<String, Object> excludedSchemes = new HashMap<>();
excludedSchemes.put("macappstores", true);
Map<String, Object> protocolHandler = new HashMap<>();
protocolHandler.put("excluded_schemes", excludedSchemes);
Map<String, Object> prefs = new HashMap<>();
prefs.put("protocol_handler", protocolHandler);
return prefs;
}
public static Object getAllowProtocolPrefs() {
Map<String, Object> appleUrl = new HashMap<>();
appleUrl.put("macappstores", true);
Map<String, Object> allowedOriginProtocolPairs = new HashMap<>();
allowedOriginProtocolPairs.put("https://apps.apple.com", appleUrl);
Map<String, Object> protocolHandler = new HashMap<>();
protocolHandler.put("allowed_origin_protocol_pairs", allowedOriginProtocolPairs);
Map<String, Object> 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;
}
}
}
本文转载自: https://blog.csdn.net/G971005287W/article/details/128819110
版权归原作者 我是Superman丶 所有, 如有侵权,请联系我们删除。
版权归原作者 我是Superman丶 所有, 如有侵权,请联系我们删除。