初始代码
This commit is contained in:
35
yunzhupaas-boot-common/yunzhupaas-common-selenium/pom.xml
Normal file
35
yunzhupaas-boot-common/yunzhupaas-common-selenium/pom.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.yunzhupaas</groupId>
|
||||
<artifactId>yunzhupaas-boot-common</artifactId>
|
||||
<version>5.2.0-RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>yunzhupaas-common-selenium</artifactId>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.yunzhupaas.selenium;
|
||||
|
||||
import com.yunzhupaas.selenium.consts.SeleniumConsts;
|
||||
import com.yunzhupaas.selenium.driver.SeleniumBrowser;
|
||||
import com.yunzhupaas.selenium.properties.SeleniumProperties;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SeleniumHelper implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static SeleniumProperties seleniumProperties;
|
||||
|
||||
|
||||
public static <T extends SeleniumBrowser<?, ?, ?>> T getBrowser() {
|
||||
SeleniumBrowser<?, ?, ?> seleniumBrowser = (SeleniumBrowser<?, ?, ?>) applicationContext.getBean(SeleniumConsts.BROWSER_BEAN_PREFIX + seleniumProperties.getBrowserType());
|
||||
return (T) seleniumBrowser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
SeleniumHelper.applicationContext = applicationContext;
|
||||
SeleniumHelper.seleniumProperties =applicationContext.getBean(SeleniumProperties.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.yunzhupaas.selenium.autoconfiguration;
|
||||
|
||||
import com.yunzhupaas.selenium.SeleniumHelper;
|
||||
import com.yunzhupaas.selenium.consts.SeleniumConsts;
|
||||
import com.yunzhupaas.selenium.driver.ChromeBrowser;
|
||||
import com.yunzhupaas.selenium.properties.SeleniumProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.*;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(SeleniumHelper.class)
|
||||
@Slf4j
|
||||
public class SeleniumAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(SeleniumConsts.SELENIUM)
|
||||
public SeleniumProperties getSeleniumProperties() {
|
||||
return new SeleniumProperties();
|
||||
}
|
||||
|
||||
@Lazy
|
||||
@ConditionalOnMissingBean(name = SeleniumConsts.BROWSER_BEAN_PREFIX + SeleniumConsts.BROWSER_TYPE_CHROME)
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
@Bean(value = SeleniumConsts.BROWSER_BEAN_PREFIX + SeleniumConsts.BROWSER_TYPE_CHROME, initMethod = "init", destroyMethod = "close")
|
||||
public ChromeBrowser getChromeBrowser() {
|
||||
if(log.isDebugEnabled()){
|
||||
log.debug(SeleniumConsts.MARKER, "Init New Chrome");
|
||||
}
|
||||
return new ChromeBrowser();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.yunzhupaas.selenium.consts;
|
||||
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.MarkerFactory;
|
||||
|
||||
public class SeleniumConsts {
|
||||
|
||||
private SeleniumConsts() {
|
||||
}
|
||||
|
||||
public static final String SELENIUM = "selenium";
|
||||
|
||||
public static final Marker MARKER = MarkerFactory.getMarker(SELENIUM);
|
||||
|
||||
public static final String BROWSER_TYPE_CHROME = "chrome";
|
||||
|
||||
public static final String BROWSER_BEAN_PREFIX = "selenium_";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.yunzhupaas.selenium.driver;
|
||||
|
||||
import com.yunzhupaas.selenium.SeleniumHelper;
|
||||
import com.yunzhupaas.selenium.consts.SeleniumConsts;
|
||||
import com.yunzhupaas.selenium.properties.SeleniumProperties;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.openqa.selenium.remote.AbstractDriverOptions;
|
||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||
import org.openqa.selenium.remote.service.DriverService;
|
||||
|
||||
@Data
|
||||
@Slf4j
|
||||
public abstract class AbstractBrowser<D extends RemoteWebDriver, S extends DriverService, O extends AbstractDriverOptions<?>> implements SeleniumBrowser<D, S, O> {
|
||||
|
||||
protected D driverInstance;
|
||||
protected S driverServiceInstance;
|
||||
protected O driverOptionsInstance;
|
||||
|
||||
|
||||
protected AbstractBrowser() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
protected AbstractBrowser(D driver, S driverService, O driverOptions) {
|
||||
this.driverInstance = driver;
|
||||
this.driverServiceInstance = driverService;
|
||||
this.driverOptionsInstance = driverOptions;
|
||||
if (this.driverInstance == null) {
|
||||
if (this.driverServiceInstance == null && this.driverOptionsInstance == null) {
|
||||
this.driverServiceInstance = buildDriverService();
|
||||
this.driverOptionsInstance = buildDriverOptions();
|
||||
}
|
||||
if(log.isDebugEnabled()){
|
||||
log.debug(SeleniumConsts.MARKER, "创建浏览器, {}, {}", this.driverServiceInstance, this.driverOptionsInstance);
|
||||
}
|
||||
this.driverInstance = buildDriver(this.driverServiceInstance, this.driverOptionsInstance);
|
||||
}
|
||||
}
|
||||
|
||||
protected static SeleniumProperties getProperties() {
|
||||
return SeleniumHelper.getSeleniumProperties();
|
||||
}
|
||||
|
||||
protected abstract O buildDriverOptions();
|
||||
|
||||
protected abstract S buildDriverService();
|
||||
|
||||
protected abstract D buildDriver(S driverService, O driverOptions);
|
||||
|
||||
D buildDriver() {
|
||||
return buildDriver(buildDriverService(), buildDriverOptions());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public D getDriver() {
|
||||
return this.driverInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public S getDriverService() {
|
||||
return this.driverServiceInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public O getDriverOptions() {
|
||||
return this.driverOptionsInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化调用
|
||||
*/
|
||||
public void init() {
|
||||
if(log.isDebugEnabled()){
|
||||
log.debug(SeleniumConsts.MARKER, "浏览器实例初始化方法调用");
|
||||
}
|
||||
if(driverInstance != null) {
|
||||
setScriptTimeout(getProperties().getScriptTimeout());
|
||||
setPageLoadTimeout(getProperties().getPageLoadTimeout());
|
||||
setImplicaitlyWaitTimeout(getProperties().getImplicaitlyWaitTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(log.isDebugEnabled()){
|
||||
log.debug(SeleniumConsts.MARKER, "浏览器实例销毁化方法调用");
|
||||
}
|
||||
if (driverInstance != null) {
|
||||
try {
|
||||
driverInstance.quit();
|
||||
} catch (Exception e) {
|
||||
log.error(SeleniumConsts.MARKER, "关闭浏览器出错", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.yunzhupaas.selenium.driver;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.chrome.ChromeDriverService;
|
||||
import org.openqa.selenium.chrome.ChromeOptions;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Slf4j
|
||||
public class ChromeBrowser extends AbstractBrowser<ChromeDriver, ChromeDriverService, ChromeOptions> {
|
||||
|
||||
public static Supplier<ChromeOptions> defaultDriverOptionsSupplier = () -> {
|
||||
System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, getProperties().getDriverPath());
|
||||
ChromeOptions options = new ChromeOptions();
|
||||
//设置浏览器参数
|
||||
options.addArguments("--headless");
|
||||
options.addArguments("--disable-gpu");
|
||||
options.addArguments("--no-sandbox");
|
||||
options.addArguments("lang=zh_CN.UTF-8");
|
||||
options.addArguments("--disable-dev-shm-usage");
|
||||
//指定浏览器分辨率
|
||||
options.addArguments("window-size=1920x1080");
|
||||
//浏览器文件
|
||||
if (StringUtils.hasText(getProperties().getBrowserPath())) {
|
||||
options.setBinary(getProperties().getBrowserPath());
|
||||
}
|
||||
return options;
|
||||
};
|
||||
public static Supplier<ChromeDriverService> defaultDriverServiceSupplier = () -> null;
|
||||
|
||||
|
||||
@Override
|
||||
public ChromeOptions buildDriverOptions() {
|
||||
return defaultDriverOptionsSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChromeDriverService buildDriverService() {
|
||||
return defaultDriverServiceSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChromeDriver buildDriver(ChromeDriverService driverService, ChromeOptions driverOptions) {
|
||||
Assert.notNull(System.getProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY), "未设置浏览器驱动路径");
|
||||
ChromeDriver driver;
|
||||
if (driverService != null && driverOptions != null) {
|
||||
driver = new ChromeDriver(driverService, driverOptions);
|
||||
} else if (driverOptions != null) {
|
||||
driver = new ChromeDriver(driverOptions);
|
||||
} else if (driverService != null) {
|
||||
driver = new ChromeDriver(driverService);
|
||||
} else {
|
||||
throw new IllegalArgumentException("service 或 options 不允许都为空");
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.yunzhupaas.selenium.driver;
|
||||
|
||||
import com.yunzhupaas.selenium.SeleniumHelper;
|
||||
import com.yunzhupaas.selenium.properties.SeleniumProperties;
|
||||
import org.openqa.selenium.*;
|
||||
import org.openqa.selenium.remote.AbstractDriverOptions;
|
||||
import org.openqa.selenium.remote.RemoteWebDriver;
|
||||
import org.openqa.selenium.remote.service.DriverService;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface SeleniumBrowser<D extends RemoteWebDriver, S extends DriverService, O extends AbstractDriverOptions<?>> {
|
||||
|
||||
D getDriver();
|
||||
|
||||
S getDriverService();
|
||||
|
||||
O getDriverOptions();
|
||||
|
||||
/**
|
||||
* 关闭驱动和浏览器
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* 设置页面加载超时时间
|
||||
*/
|
||||
default void setPageLoadTimeout(Duration duration) {
|
||||
getDriver().manage().timeouts().pageLoadTimeout(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置查找元素超时时间
|
||||
*/
|
||||
default void setImplicaitlyWaitTimeout(Duration duration) {
|
||||
getDriver().manage().timeouts().implicitlyWait(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置执行脚本超时时间
|
||||
*/
|
||||
default void setScriptTimeout(Duration duration) {
|
||||
getDriver().manage().timeouts().scriptTimeout(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 寻找元素, 若不存在抛出未找到元素异常
|
||||
* 如需判断元素是否存在可调用{@link #findElements} 进行判空处理, 为空获取默认超时配置 {@link SeleniumProperties#getImplicaitlyWaitTimeout()}
|
||||
*
|
||||
* @param locator 查找条件
|
||||
* @param findTimeout 最长等待时间
|
||||
*/
|
||||
default WebElement findElement(By locator, Duration findTimeout) {
|
||||
findTimeout = findTimeout == null ? SeleniumHelper.getSeleniumProperties().getImplicaitlyWaitTimeout() : findTimeout;
|
||||
setImplicaitlyWaitTimeout(findTimeout);
|
||||
return getDriver().findElement(locator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 寻找元素, 未找到元素返回空
|
||||
*
|
||||
* @param locator 查找条件
|
||||
* @param findTimeout 最长等待时间, 为空获取默认超时配置 {@link SeleniumProperties#getImplicaitlyWaitTimeout()}
|
||||
*/
|
||||
default List<WebElement> findElements(By locator, Duration findTimeout) {
|
||||
findTimeout = findTimeout == null ? SeleniumHelper.getSeleniumProperties().getImplicaitlyWaitTimeout() : findTimeout;
|
||||
setImplicaitlyWaitTimeout(findTimeout);
|
||||
return getDriver().findElements(locator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载页面
|
||||
* @param url 网页地址
|
||||
* @param loadTimeout 加载超时时间, 为空获取默认超时配置 {@link SeleniumProperties#getPageLoadTimeout()}
|
||||
* @param newTab 新窗口打开链接
|
||||
*/
|
||||
default void loadPage(String url, Duration loadTimeout, WindowType newTab) {
|
||||
if (newTab != null) {
|
||||
getDriver().switchTo().newWindow(newTab);
|
||||
}
|
||||
loadTimeout = loadTimeout == null ? SeleniumHelper.getSeleniumProperties().getPageLoadTimeout() : loadTimeout;
|
||||
setPageLoadTimeout(loadTimeout);
|
||||
getDriver().get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行JS脚本
|
||||
* @param script 脚本内容
|
||||
* @param scriptTimeout 脚本执行超时时间, 为空获取默认超时配置 {@link SeleniumProperties#getScriptTimeout()}
|
||||
* @param args 脚本内容参数
|
||||
*/
|
||||
default Object executeScript(String script, Duration scriptTimeout, Object... args){
|
||||
scriptTimeout = scriptTimeout == null ? SeleniumHelper.getSeleniumProperties().getScriptTimeout() : scriptTimeout;
|
||||
setScriptTimeout(scriptTimeout);
|
||||
return getDriver().executeScript(script, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最大的页面大小
|
||||
*/
|
||||
default Dimension getDocumentSize() {
|
||||
Map<String, Long> result = (Map<String, Long>) getDriver().executeScript("return {'w':Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth), 'h':Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight)}");
|
||||
return new Dimension(Math.toIntExact(result.get("w")), Math.toIntExact(result.get("h")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 窗口最大化, 截取全部网页内容
|
||||
*/
|
||||
default byte[] screenShotByWindow() {
|
||||
getDriver().manage().window().setSize(getDocumentSize());
|
||||
return getDriver().getScreenshotAs(OutputType.BYTES);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 窗口最大化, 截取指定元素
|
||||
*/
|
||||
default byte[] screenShotByElement(WebElement element) {
|
||||
getDriver().manage().window().setSize(getDocumentSize());
|
||||
return element.getScreenshotAs(OutputType.BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 可能存在懒加载, 滚动页面到底部进行触发, 每次滚动完后延时指定时间等待触发
|
||||
* @param scrollDelay 每次滚动完后延时, 等待触发
|
||||
*/
|
||||
default void scrollToBottom(Duration scrollDelay) {
|
||||
Dimension documentSize = getDocumentSize();
|
||||
long height = documentSize.getHeight();
|
||||
//这里需要模拟滑动,有些是滑动的时候才加载的
|
||||
long temp_height = 0;
|
||||
while (true) {
|
||||
temp_height += 500;
|
||||
if (temp_height >= height) {
|
||||
break;
|
||||
}
|
||||
getDriver().executeScript("window.scrollBy(0,500)");
|
||||
try {
|
||||
Thread.sleep(scrollDelay.toMillis());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.yunzhupaas.selenium.properties;
|
||||
|
||||
import com.yunzhupaas.selenium.consts.SeleniumConsts;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Data
|
||||
public class SeleniumProperties {
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browserType = SeleniumConsts.BROWSER_TYPE_CHROME;
|
||||
|
||||
/**
|
||||
* 浏览器路径
|
||||
*/
|
||||
private String browserPath;
|
||||
|
||||
/**
|
||||
* 浏览器驱动路径
|
||||
*/
|
||||
private String driverPath;
|
||||
|
||||
/**
|
||||
* 页面加载超时时间
|
||||
*/
|
||||
private Duration pageLoadTimeout = Duration.ofSeconds(30L);
|
||||
|
||||
|
||||
/**
|
||||
* 查找元素超时时间
|
||||
*/
|
||||
private Duration implicaitlyWaitTimeout = Duration.ofSeconds(30L);
|
||||
|
||||
|
||||
/**
|
||||
* 执行脚本超时时间
|
||||
*/
|
||||
private Duration scriptTimeout = Duration.ofSeconds(30L);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
com.yunzhupaas.selenium.autoconfiguration.SeleniumAutoConfiguration
|
||||
Reference in New Issue
Block a user