查询系统架构
uname -m
系统架构aarch64,arm都可以使用
1.安装Node.js
- 可按照搜索安装进行安装(注意的是Node的版本不能太低,至少要18版本)
- Node.js压缩包node-v20.18.0-linux-arm64.tar.xz
- 解压并配置环境变量
tar -xf node-v20.18.0-linux-arm64.tar.xz -C /opt/
sudo mv /opt/node-v20.18.0-linux-arm64 /opt/node
echo 'export PATH=/opt/node/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
node -v # 验证 v20.x
npm -v
2.下载 Playwright NPM 包及依赖
- 忽略版本冲突,全局安装
npm install -g playwright --legacy-peer-deps
- 全局安装
npm install -g playwright

- 验证是否安装
playwright --version
3.下载二进制浏览器
npx playwright install --with-deps chromium firefox webkit
playwright install --with-deps chromium firefox webkit
playwright install chromium firefox webkit

- 指定浏览器路径,指定 Playwright 浏览器二进制文件的下载位置
echo 'export PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/ms-playwright' >> ~/.bashrc
source ~/.bashrc
echo $PLAYWRIGHT_BROWSERS_PATH
4.下载系统依赖
- Playwright 运行所需系统依赖
yum install -y libX11 libXcomposite libXdamage libXext libXi libXtst libXrandr \ alsa-lib atk at-spi2-atk at-spi2-core cairo cups-libs dbus-libs expat \ fontconfig freetype gdk-pixbuf2 glib2 gtk3 libdrm libffi libICE libSM \ libXcursor libXfixes libXinerama libXpm libXss libXv libXxf86vm libxcb \ libxkbcommon libxkbcommon-x11 mesa-libgbm nss pango wayland-libs-client \ wayland-libs-cursor wayland-libs-egl
yum install -y libX11 libXcomposite libXdamage libXext libXi libXtst libXrandr \ alsa-lib atk at-spi2-atk at-spi2-core cairo cups-libs dbus-libs expat \ fontconfig freetype gdk-pixbuf2 glib2 gtk3 libdrm libffi libICE libSM \ libXcursor libXfixes libXinerama libXpm libXss libXv libXxf86vm libxcb \ libxkbcommon libxkbcommon-x11 mesa-libgbm nss pango wayland-libs-client \ wayland-libs-cursor wayland-libs-egl
如遇到依赖包找不到 名称不匹配时 使用命令查询匹配的命令
yum search XXXX
如果是国产操作系统(麒麟系统),这几个包是找不到的
alsa-lib fontconfig libXcursor libXss libxkbcommon wayland-libs-client wayland-libs-cursor wayland-libs-egl
上述包在麒麟系统对应的包下载命令
yum install -y alsa-lib.aarch64 alsa-lib-devel.aarch64
yum install -y fontconfig.aarch64 fontconfig-devel.aarch64 fontconfig-help.noarch
yum install -y libXcursor.aarch64 libXcursor-devel.aarch64 libXcursor-help.noarch
yum install -y libXScrnSaver.aarch64
yum install -y libxkbcommon.aarch64 libxkbcommon-devel.aarch64
yum install -y libwayland-client libwayland-cursor libwayland-egl
5.配置index.js执行转换脚本
mkdir -p /opt/ultimate-solution
cd /opt/ultimate-solution
- 搜索整个系统,忽略权限错误,只找可执行的 chrome;逐个验证找到的路径,直到找到能用的
find / -type f \( -name "chrome" -o -name "headless_shell" \) -executable 2>/dev/null | grep -E "playwright|ms-playwright"
- 替换为你上面 find 到的第一个路径,验证版本
/root/.cache/ms-playwright/chromium-1097/chrome-linux/chrome --version
- js脚本内容
const { chromium } = require('playwright');
const fs = require('fs');
async function convertHtmlToPdf() {
const htmlInputPath = process.argv[2];
const pdfOutputPath = process.argv[3];
if (!htmlInputPath || !pdfOutputPath) {
console.error('Usage: node index.js <HTML_FILE_PATH> <PDF_OUTPUT_PATH>');
process.exit(1);
}
// 启动 Playwright 浏览器
const browser = await chromium.launch({
// --------------------------
// 这里必须替换为你步骤2验证成功的完整路径!!!
// 测试环境:/root/.cache/ms-playwright/chromium-1208/chrome-linux/chrome
executablePath: '/root/.cache/ms-playwright/chromium-1217/chrome-linux/chrome',
headless: true,
args: ['--no-sandbox', '--disable-gpu']
});
try {
const page = await browser.newPage();
// 读取 HTML 文件
const htmlContent = fs.readFileSync(htmlInputPath, 'utf-8');
// 加载 HTML 并等待渲染
await page.setContent(htmlContent, {
waitUntil: 'networkidle',
timeout: 60000
});
// 生成 PDF(A4 格式,支持背景)
await page.pdf({
path: pdfOutputPath,
format: 'A4',
printBackground: true,
margin: { top: '1cm', bottom: '1cm', left: '1cm', right: '1cm' }
});
console.log('PDF generated successfully:', pdfOutputPath);
} finally {
// 确保浏览器关闭
await browser.close();
}
}
// 执行转换
convertHtmlToPdf().catch(err => {
console.error('Error generating PDF:', err);
process.exit(1);
});
- 进行验证
node /opt/ultimate-solution/index.js
可能遇到的问题:
Node.js 的设计机制是:全局安装的包(-g)默认不会被本地代码引用。即使你全局装了 Playwright,你的项目文件夹里仍然需要一个本地的 node_modules
#1.进入项目目录
cd /opt/ekp-ultimate-solution/
# 2. 执行本地安装(不要加 -g)
npm install playwright
6.后端代码调用返回文件
public class HeadlessBrowserUtil implements AutoCloseable {
private static final Logger logger = LoggerFactory.getLogger(HeadlessBrowserUtil.class);
private static Config config;
static {
try {
config = new Config();
} catch (Exception e) {
logger.error("配置初始化失败", e);
config = null;
}
}
/**
* 常量定义(提升维护性)
* */
private static final long DEFAULT_TIMEOUT_SECONDS = 30;
private static final String DEFAULT_PDF_PAGE_SIZE = "A4";
private static final boolean DEFAULT_PRINT_BACKGROUND = true;
private static final String DEFAULT_CHROME_DRIVER_PATH;
private static final String DEFAULT_HEAD_LESS_SHELL_PATH;
private static final String NEW_VERSION_HEAD_LESS_PATH;
static {
if (config != null) {
DEFAULT_CHROME_DRIVER_PATH = config.getChromeDriverPath();
DEFAULT_HEAD_LESS_SHELL_PATH = config.getChromeHeadlessShellPath();
NEW_VERSION_HEAD_LESS_PATH = config.getNewVersionHeadlessPath();
} else {
DEFAULT_CHROME_DRIVER_PATH = "/usr/bin/chromedriver";
DEFAULT_HEAD_LESS_SHELL_PATH = "/home/chroma/chrome-headless-shell-linux64/chrome-headless-shell";
NEW_VERSION_HEAD_LESS_PATH = "/opt/ultimate-solution/index.js";
}
}
private WebDriver driver;
private WebDriverWait defaultWait;
private final long defaultTimeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
// ========== 构造方法 ==========
public HeadlessBrowserUtil() {}
// public HeadlessBrowserUtil(String init) {
// this(DEFAULT_TIMEOUT_SECONDS);
//
// }
public HeadlessBrowserUtil(long defaultTimeoutSeconds) {
// this.defaultTimeoutSeconds = defaultTimeoutSeconds;
initDriver();
}
/**
* 自定义 ChromeOptions 的构造方法
*/
public HeadlessBrowserUtil(ChromeOptions customOptions) {
this(customOptions, DEFAULT_TIMEOUT_SECONDS);
}
public HeadlessBrowserUtil(ChromeOptions customOptions, long defaultTimeoutSeconds) {
// this.defaultTimeoutSeconds = defaultTimeoutSeconds;
try {
this.driver = new ChromeDriver(customOptions);
this.defaultWait = new WebDriverWait(driver, Duration.ofSeconds(defaultTimeoutSeconds));
logger.info("ChromeDriver初始化成功(自定义Options)");
} catch (Exception e) {
logger.error("ChromeDriver初始化失败(自定义Options)", e);
throw new RuntimeException("ChromeDriver初始化失败", e);
}
}
// ========== 初始化 ==========
// 先在类顶部新增常量(替换为你的ChromeDriver实际路径)
// private static final String DEFAULT_HEAD_LESS_SHELL_PATH = "/home/fengxh/DevEnv/chroma/chrome-headless-shell-linux64/chrome-headless-shell";
private void initDriver() {
ChromeOptions options = new ChromeOptions();
// 1. 显式指定ChromeDriver路径(关键!避免系统加载旧版本)
System.setProperty("webdriver.chrome.driver", DEFAULT_CHROME_DRIVER_PATH);
// 2. 适配144版本的无头参数(精简+兼容)
options.setBinary(DEFAULT_HEAD_LESS_SHELL_PATH);
options.addArguments("--headless=new"); // 144版本推荐的无头模式
options.addArguments("--disable-gpu"); // 兼容Linux无GPU环境
options.addArguments("--window-size=1920,1080");
options.addArguments("--remote-allow-origins=*");// 解决跨域限制
options.addArguments("--disable-dev-shm-usage"); // 关键!Linux下避免/dev/shm内存不足
options.addArguments("--no-sandbox"); // 非root用户运行必需(Linux常见问题)
options.addArguments("--disable-extensions"); // 禁用扩展,减少干扰
// 以下参数144版本可保留,不影响兼容
options.addArguments("--disable-blink-features=AutomationControlled");
options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"});
try {
this.driver = new ChromeDriver(options);
this.defaultWait = new WebDriverWait(driver, Duration.ofSeconds(defaultTimeoutSeconds));
logger.info("ChromeDriver初始化成功,默认超时时间={}秒,ChromeDriver路径={}",
defaultTimeoutSeconds, DEFAULT_CHROME_DRIVER_PATH);
} catch (Exception e) {
// 补充详细错误日志(路径、版本、异常栈)
logger.error("===== ChromeDriver初始化失败详情 =====", e);
logger.error("1. ChromeDriver路径:{}", DEFAULT_CHROME_DRIVER_PATH);
logger.error("2. Headless Shell路径:{}", DEFAULT_HEAD_LESS_SHELL_PATH);
logger.error("3. 异常类型:{}", e.getClass().getName());
logger.error("4. 异常信息:{}", e.getMessage());
throw new RuntimeException("无头浏览器初始化失败,请检查日志中路径/版本/依赖", e);
}
}
// ========== 核心新增:生成 PDF byte[] 方法 ==========
/**
* 生成当前页面的 PDF 字节数组(基于 CDP,无临时文件)
* @return PDF 字节数组
*/
public byte[] generatePdfAsBytes() {
return generatePdfAsBytes(DEFAULT_PDF_PAGE_SIZE, DEFAULT_PRINT_BACKGROUND, false);
}
/**
* 自定义 PDF 参数生成字节数组
* @param pageSize 页面大小(A4/Letter/Legal/A3 等)
* @param printBackground 是否打印背景色/图片
* @param removeMargins 是否移除打印边距
* @return PDF 字节数组
*/
public byte[] generatePdfAsBytes(String pageSize, boolean printBackground, boolean removeMargins) {
try {
// 1. 等待页面完全渲染(确保异步资源加载完成)
waitForPageLoad();
waitForAllImagesLoaded();
logger.info("页面渲染完成,开始通过CDP生成PDF");
// 2. 构造CDP打印参数
Map<String, Object> printParams = new HashMap<>();
printParams.put("paperWidth", getPageWidth(pageSize)); // 宽度(英寸)
printParams.put("paperHeight", getPageHeight(pageSize)); // 高度(英寸)
printParams.put("printBackground", printBackground); // 打印背景
printParams.put("marginTop", removeMargins ? 0 : 0.4); // 上边距(英寸)
printParams.put("marginBottom", removeMargins ? 0 : 0.4); // 下边距
printParams.put("marginLeft", removeMargins ? 0 : 0.4); // 左边距
printParams.put("marginRight", removeMargins ? 0 : 0.4); // 右边距
printParams.put("preferCSSPageSize", true); // 优先使用CSS定义的页面大小
printParams.put("transferMode", "ReturnAsBase64"); // 返回Base64格式
// 3. 调用CDP的Page.printToPDF方法
ChromeDriver chromeDriver = (ChromeDriver) this.driver;
Map<String, Object> result = chromeDriver.executeCdpCommand("Page.printToPDF", printParams);
String pdfBase64 = (String) result.get("data");
// 4. Base64转byte[]
byte[] pdfBytes = java.util.Base64.getDecoder().decode(pdfBase64);
logger.info("PDF生成成功,字节数={}", pdfBytes.length);
return pdfBytes;
} catch (Exception e) {
logger.error("生成PDF字节数组失败", e);
throw new RuntimeException("PDF生成失败", e);
}
}
/**
* 注入HTML字符串并生成PDF字节数组(一站式调用)
* @param htmlContent HTML字符串
* @return PDF字节数组
*/
public byte[] generatePdfFromHtml(String htmlContent) {
// 注入HTML并等待渲染
injectHtml(htmlContent);
// 生成PDF
return generatePdfAsBytes();
}
// ========== 核心PDF生成方法(新方案) ==========
/**
* Playwright 转换
* 通过HTML内容生成PDF(推荐使用)(适配国产麒麟操作系统新方案)
*/
public byte[] generatePdfFromHtml(String htmlContent,String version) {
Path tempHtml = null;
Path tempPdf = null;
try {
// 1. 从配置读取工具路径
String toolPath = NEW_VERSION_HEAD_LESS_PATH;
if (StringUtil.isNull(toolPath)) {
toolPath = "/opt/ultimate-solution/index.js";
logger.warn("未配置pdfToolPath,使用默认路径: {}", toolPath);
}
// 2. 创建临时HTML文件
tempHtml = Files.createTempFile("ekp-archive-", ".html");
Files.write(tempHtml, htmlContent.getBytes(StandardCharsets.UTF_8));
logger.info("创建临时HTML文件: {}", tempHtml.toAbsolutePath());
// 3. 创建临时PDF文件路径
tempPdf = Files.createTempFile("ekp-archive-", ".pdf");
// 确保文件不存在
Files.deleteIfExists(tempPdf);
logger.info("指定PDF输出路径: {}", tempPdf.toAbsolutePath());
// 4. 构造并执行命令
List<String> command = Arrays.asList(
"node",
toolPath,
tempHtml.toAbsolutePath().toString(),
tempPdf.toAbsolutePath().toString()
);
logger.info("执行命令: {}", String.join(" ", command));
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process process = pb.start();
// 5. 读取执行结果
// 5. 读取执行结果
String output = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);
int exitCode = process.waitFor();
logger.info("命令执行完成,退出码: {}, 输出: {}", exitCode, output);
if (exitCode != 0) {
throw new RuntimeException("PDF工具执行失败,退出码: " + exitCode + ",输出: " + output);
}
// 6. 检查并读取PDF
if (!Files.exists(tempPdf) || Files.size(tempPdf) == 0) {
throw new RuntimeException("PDF文件生成失败: " + tempPdf.toAbsolutePath());
}
byte[] pdfBytes = Files.readAllBytes(tempPdf);
logger.info("PDF生成成功,大小: {} 字节", pdfBytes.length);
return pdfBytes;
} catch (Exception e) {
logger.error("PDF生成失败", e);
throw new RuntimeException("PDF生成失败: " + e.getMessage(), e);
} finally {
// 7. 清理临时文件
if (tempHtml != null) {
try { Files.deleteIfExists(tempHtml); } catch (Exception ex) { logger.error("清理HTML失败", ex); }
}
if (tempPdf != null) {
try { Files.deleteIfExists(tempPdf); } catch (Exception ex) { logger.error("清理PDF失败", ex); }
}
}
}
// ========== 辅助方法 ==========
/**
* 注入HTML字符串到空白页(解决本地HTML渲染问题)
*/
public HeadlessBrowserUtil injectHtml(String htmlContent) {
try {
// 打开空白页
get("about:blank").waitForPageLoad();
// 注入HTML并关闭文档流(避免渲染异常)
executeScript("document.write(arguments[0]); document.close();", htmlContent);
logger.info("HTML字符串注入完成,开始等待渲染");
// 等待页面完全渲染(含图片/异步JS)
waitForPageLoad();
waitForAllImagesLoaded();
logger.info("HTML渲染完成");
return this;
} catch (Exception e) {
logger.error("HTML注入/渲染失败", e);
throw new RuntimeException("HTML注入失败", e);
}
}
/**
* 等待所有图片加载完成(避免PDF缺图)
* JDK8 适配点:
* 1. 移除字符串文本块(JDK15+支持),替换为字符串拼接
* 2. 确保 Lambda 泛型推导兼容 JDK8
*/
/**
* 等待所有图片加载完成(避免PDF缺图)
* 修复点:
* 1. JS脚本统一返回数值(0/1),避免布尔值导致类型转换异常
* 2. Java端接收Number类型,兼容Long/Integer等数值类型
* 3. 简化逻辑判断,直接基于数值判断是否加载完成
*/
private void waitForAllImagesLoaded() {
waitForCondition((Function<WebDriver, Boolean>) webDriver -> {
// 修正JS脚本:统一返回数值(1=加载完成,0=未完成)
Number result = (Number) ((JavascriptExecutor) webDriver).executeScript(
"var images = document.images;" +
"if (images.length === 0) return 1;" + // 无图片时返回1(完成)
"var loaded = 0;" +
"for (var i = 0; i < images.length; i++) {" +
" if (images[i].complete && !images[i].error) loaded++;" +
"}" +
"return loaded === images.length ? 1 : 0;" // 有图片时,完成=1,未完成=0
);
// 数值转int,判断是否等于1(加载完成)
return result.intValue() == 1;
}, defaultTimeoutSeconds);
}
/**
* 页面大小转英寸(CDP的printToPDF参数要求英寸单位)
* JDK8 适配点:移除 switch 表达式(JDK14+支持),替换为 switch 语句
*/
private double getPageWidth(String pageSize) {
String upperPageSize = pageSize.toUpperCase();
switch (upperPageSize) {
case "A4":
return 8.27;
case "A3":
return 11.69;
case "LETTER":
return 8.5;
case "LEGAL":
return 8.5;
default:
return 8.27; // 默认A4
}
}
/**
* 页面高度转英寸
* JDK8 适配点:移除 switch 表达式(JDK14+支持),替换为 switch 语句
*/
private double getPageHeight(String pageSize) {
String upperPageSize = pageSize.toUpperCase();
switch (upperPageSize) {
case "A4":
return 11.69;
case "A3":
return 16.54;
case "LETTER":
return 11.0;
case "LEGAL":
return 14.0;
default:
return 11.69; // 默认A4
}
}
// ========== 备选方案:临时文件方式(兼容低版本ChromeDriver) ==========
/**
* 临时文件方式生成PDF byte[](若CDP调用失败时使用)
* @param tempPdfPath 临时文件路径
* @return PDF字节数组
*/
public byte[] generatePdfByTempFile(String tempPdfPath) {
// 1. 构造带打印参数的ChromeOptions
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless=new");
options.addArguments("--disable-gpu");
options.addArguments("--print-to-pdf=" + tempPdfPath);
options.addArguments("--print-to-pdf-page-size=" + DEFAULT_PDF_PAGE_SIZE);
options.addArguments("--print-backgrounds=" + DEFAULT_PRINT_BACKGROUND);
options.addArguments("--no-margins");
// 2. 重新初始化Driver(必须重新创建才能生效打印参数)
WebDriver tempDriver = new ChromeDriver(options);
try {
// 3. 复制当前页面的URL/HTML(保持上下文)
tempDriver.get(this.driver.getCurrentUrl());
WebDriverWait tempWait = new WebDriverWait(tempDriver, Duration.ofSeconds(defaultTimeoutSeconds));
tempWait.until(webDriver -> ((JavascriptExecutor) webDriver)
.executeScript("return document.readyState").equals("complete"));
// 4. 读取临时文件并转byte[]
File pdfFile = new File(tempPdfPath);
if (!pdfFile.exists() || pdfFile.length() == 0) {
throw new RuntimeException("临时PDF文件生成失败:" + tempPdfPath);
}
byte[] pdfBytes = Files.readAllBytes(pdfFile.toPath());
logger.info("临时文件方式生成PDF成功,字节数={}", pdfBytes.length);
return pdfBytes;
} catch (Exception e) {
logger.error("临时文件方式生成PDF失败", e);
throw new RuntimeException("PDF生成失败", e);
} finally {
// 5. 清理临时文件+关闭临时Driver
tempDriver.quit();
File pdfFile = new File(tempPdfPath);
if (pdfFile.exists() && !pdfFile.delete()) {
logger.warn("临时PDF文件清理失败:{}", tempPdfPath);
}
}
}
// ========== 原有方法保留 + 少量优化 ==========
public HeadlessBrowserUtil get(String url) {
try {
driver.get(url);
logger.debug("访问URL:{}", url);
return this;
} catch (Exception e) {
logger.error("访问URL失败:{}", url, e);
throw new RuntimeException("访问URL失败", e);
}
}
public Object executeScript(String script, Object... args) {
try {
return ((JavascriptExecutor) driver).executeScript(script, args);
} catch (Exception e) {
logger.error("执行JS脚本失败:{}", script.substring(0, Math.min(script.length(), 100)), e);
throw new RuntimeException("JS脚本执行失败", e);
}
}
public Object executeAsyncScript(String script, Object... args) {
try {
return ((JavascriptExecutor) driver).executeAsyncScript(script, args);
} catch (Exception e) {
logger.error("执行异步JS脚本失败", e);
throw new RuntimeException("异步JS脚本执行失败", e);
}
}
public WebElement waitForElement(By locator) {
return defaultWait.until(ExpectedConditions.presenceOfElementLocated(locator));
}
public WebElement waitForElement(By locator, long timeoutSeconds) {
return new WebDriverWait(driver, Duration.ofSeconds(timeoutSeconds))
.until(ExpectedConditions.presenceOfElementLocated(locator));
}
public WebElement waitForElementVisible(By locator) {
return defaultWait.until(ExpectedConditions.visibilityOfElementLocated(locator));
}
public WebElement waitForElementClickable(By locator) {
return defaultWait.until(ExpectedConditions.elementToBeClickable(locator));
}
public boolean waitForTextContains(By locator, String text) {
return defaultWait.until(ExpectedConditions.textToBePresentInElementLocated(locator, text));
}
public boolean waitForAttributeValue(By locator, String attribute, String value) {
return defaultWait.until(ExpectedConditions.attributeToBe(locator, attribute, value));
}
public boolean waitForTitleContains(String title) {
return defaultWait.until(ExpectedConditions.titleContains(title));
}
public boolean waitForTitleIs(String title) {
return defaultWait.until(ExpectedConditions.titleIs(title));
}
public WebElement waitForJsCompleteMarker(String markerId) {
return waitForElement(By.id(markerId));
}
public int[] waitForJsCompleteWithResult(String markerId, String successAttr, String failAttr) {
WebElement marker = waitForElement(By.id(markerId));
String success = marker.getAttribute(successAttr);
String fail = marker.getAttribute(failAttr);
return new int[]{
Integer.parseInt(success != null ? success : "0"),
Integer.parseInt(fail != null ? fail : "0")
};
}
public String waitForJsCompleteSimple(String inputId) {
WebElement input = waitForElement(By.id(inputId));
new WebDriverWait(driver, Duration.ofSeconds(defaultTimeoutSeconds))
.until((Function<WebDriver, Boolean>) d -> {
String val = input.getAttribute("value");
return val != null && !val.isEmpty();
});
return input.getAttribute("value");
}
public boolean waitForBodyDataAttribute(String attributeName, String expectedValue) {
String fullAttr = "data-" + attributeName;
return defaultWait.until(ExpectedConditions.attributeToBe(By.tagName("body"), fullAttr, expectedValue));
}
public <T> T waitForCondition(Function<WebDriver, T> condition, long timeoutSeconds) {
return new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(timeoutSeconds))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class, StaleElementReferenceException.class) // 增加异常忽略
.until(condition);
}
public WebElement findElement(By locator) {
return driver.findElement(locator);
}
public List<WebElement> findElements(By locator) {
return driver.findElements(locator);
}
public HeadlessBrowserUtil click(By locator) {
waitForElementClickable(locator).click();
return this;
}
public HeadlessBrowserUtil sendKeys(By locator, String text) {
WebElement element = waitForElementVisible(locator);
element.clear();
element.sendKeys(text);
return this;
}
public String getText(By locator) {
return waitForElementVisible(locator).getText();
}
public String getPageSource() {
return driver.getPageSource();
}
public String getCurrentUrl() {
return driver.getCurrentUrl();
}
public String getTitle() {
return driver.getTitle();
}
public HeadlessBrowserUtil refresh() {
driver.navigate().refresh();
return this;
}
public HeadlessBrowserUtil back() {
driver.navigate().back();
return this;
}
public HeadlessBrowserUtil forward() {
driver.navigate().forward();
return this;
}
public byte[] takeScreenshot() {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
}
public File takeScreenshotAsFile() {
return ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
}
public HeadlessBrowserUtil switchToFrame(By locator) {
driver.switchTo().frame(waitForElement(locator));
return this;
}
public HeadlessBrowserUtil switchToDefaultContent() {
driver.switchTo().defaultContent();
return this;
}
/**
* 【过时】无头模式下无效,建议使用 generatePdfAsBytes()
*/
@Deprecated
public HeadlessBrowserUtil triggerPrint() {
logger.warn("triggerPrint()方法在无头模式下无效,请使用generatePdfAsBytes()生成PDF");
Actions actions = new Actions(driver);
actions.keyDown(Keys.CONTROL).sendKeys("p").keyUp(Keys.CONTROL).perform();
return this;
}
public HeadlessBrowserUtil sleep(long seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return this;
}
public HeadlessBrowserUtil waitForPageLoad() {
defaultWait.until(webDriver -> ((JavascriptExecutor) webDriver)
.executeScript("return document.readyState").equals("complete"));
return this;
}
public HeadlessBrowserUtil waitForLibraryLoad(String libraryName) {
defaultWait.until(webDriver -> ((JavascriptExecutor) webDriver)
.executeScript("return typeof " + libraryName + " !== 'undefined'").equals(true));
return this;
}
@Override
public void close() {
if (driver != null) {
try {
driver.quit();
logger.info("ChromeDriver已正常关闭");
} catch (Exception e) {
logger.error("ChromeDriver关闭失败", e);
} finally {
driver = null;
}
}
}
public WebDriver getDriver() {
return driver;
}
public HeadlessBrowserUtil setDefaultTimeout(long seconds) {
this.defaultWait = new WebDriverWait(driver, Duration.ofSeconds(seconds));
return this;
}
}
1万+

被折叠的 条评论
为什么被折叠?



