背景:
項(xiàng)目中想要對(duì)某個(gè)頁(yè)面進(jìn)行截圖先馆,作為縮略圖展示发框,但是希望在后臺(tái)自動(dòng)進(jìn)行,而不需要用戶手動(dòng)執(zhí)行煤墙。所以能想到的辦法就是通過(guò)前端給一個(gè)鏈接梅惯,后端在鏈接上拼接對(duì)應(yīng)的參數(shù),來(lái)獲取指定的頁(yè)面仿野,然后通過(guò)一個(gè)方法铣减,對(duì)輸入的網(wǎng)頁(yè)進(jìn)行截圖保存。
實(shí)現(xiàn):
在Java中實(shí)現(xiàn)對(duì)一個(gè)給定鏈接的網(wǎng)頁(yè)內(nèi)容加載完畢后進(jìn)行截圖并保存脚作,通常需要結(jié)合瀏覽器內(nèi)核(如使用headless模式的Chrome或Firefox)和自動(dòng)化工具葫哗。以下是一個(gè)基于Selenium WebDriver與Chromedriver的示例步驟:
引入依賴
(需要注意selenium-java這個(gè)依賴中并不包含最新版本的selenium其他依賴,所以要手動(dòng)加一下,否則其他依賴都是很老的版本劣针,會(huì)有找不到類的報(bào)錯(cuò))
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.16.1</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>4.16.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>4.16.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>4.16.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>4.16.1</version>
</dependency>
測(cè)試代碼
public static void main(String[] args) {
// 設(shè)置ChromeDriver路徑(如果WebDriverManager未自動(dòng)處理)
WebDriverManager.chromedriver().setup();
// 啟用Headless模式(可選桨螺,用于無(wú)界面截圖)
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless", "--disable-gpu");
options.addArguments("--window-size=1920,1080");
// 創(chuàng)建WebDriver實(shí)例
WebDriver driver = new ChromeDriver(options);
try {
List<String> urls = new ArrayList<>();
urls.add("https://www.baidu.com/");
urls.add("http://www.reibang.com/");
urls.forEach(url -> {
driver.get(url);
try {
Thread.sleep(3000); // 延遲5秒,僅供參考酿秸,請(qǐng)根據(jù)實(shí)際情況調(diào)整
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 截取全屏圖片
TakesScreenshot takesScreenshot = (TakesScreenshot) driver;
byte[] screenshotData = takesScreenshot.getScreenshotAs(OutputType.BYTES);
// 保存截圖到文件
BufferedImage fullImage;
try {
fullImage = ImageIO.read(((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE));
} catch (IOException e) {
throw new RuntimeException(e);
}
// 保存全屏截圖到本地灭翔,根據(jù)URL生成不同的文件名
String fileName = url.replaceAll("[^a-zA-Z0-9]", "_") + ".png";
File screenshotFile = new File(fileName);
try {
ImageIO.write(fullImage, "PNG", screenshotFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
driver.navigate().refresh();
});
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關(guān)閉瀏覽器
driver.quit();
}
}
以上是在本地運(yùn)行時(shí)所使用的代碼,當(dāng)部署到服務(wù)器上時(shí)辣苏,與本地運(yùn)行大有不同(因?yàn)楸镜匮b有谷歌瀏覽器)
在生產(chǎn)環(huán)境中使用的方法如下
安裝chrome鏡像
selenium有專門的谷歌瀏覽器以及驅(qū)動(dòng)鏡像肝箱,直接拉取這個(gè)鏡像selenium/standalone-chrome(它包含了 Selenium Grid 服務(wù)器和一個(gè)預(yù)配置好的 Chrome 瀏覽器環(huán)境。使用這個(gè)鏡像無(wú)需在本地安裝和配置 Selenium 以及瀏覽器驅(qū)動(dòng))稀蟋。在容器中運(yùn)行煌张,命令是docker run -d -p 4444:4444 --shm-size=2g selenium/standalone-chrome,其中--shm-size=2g是用于設(shè)置容器的共享內(nèi)存大型丝汀(如果沒(méi)有足夠的共享內(nèi)存骏融,瀏覽器可能會(huì)遇到性能問(wèn)題或直接崩潰)。
@PostMapping(value = "/test")
public void test() throws MalformedURLException {
// 啟用Headless模式(可選萌狂,用于無(wú)界面截圖)
ChromeOptions options = new ChromeOptions();
options.addArguments("--disable-gpu");
options.addArguments("--window-size=1920,1080");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
// 創(chuàng)建指向Selenium Grid的RemoteWebDriver實(shí)例档玻,url部分為容器中的chrome地址
WebDriver driver = new RemoteWebDriver(new URL("http://0.0.0.0:4444/wd/hub"), capabilities);
try {
List<String> urls = new ArrayList<>();
urls.add("https://www.baidu.com/");
urls.add("http://www.reibang.com/");
urls.forEach(url -> {
driver.get(url);
try {
Thread.sleep(10000); // 延遲5秒,僅供參考茫藏,請(qǐng)根據(jù)實(shí)際情況調(diào)整
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 保存截圖到文件
BufferedImage fullImage;
try {
fullImage = ImageIO.read(((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE));
} catch (IOException e) {
throw new RuntimeException(e);
}
// 保存全屏截圖到本地误趴,根據(jù)URL生成不同的文件名
String fileName = url.replaceAll("[^a-zA-Z0-9]", "_") + ".png";
File screenshotFile = new File(fileName);
try {
ImageIO.write(fullImage, "PNG", screenshotFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
driver.navigate().refresh();
});
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關(guān)閉瀏覽器
driver.quit();
}
}