Java+Selenium实现网页截图
概述
使用Java语言,实现网页截图。本文仅考虑Selenium方案,如果对其他方案感兴趣,可参考Java实现HTML页面截图功能
实现
大名鼎鼎的自动化测试工具,引入最新稳定版依赖:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
直接上代码:
public static void snapshotBySelenium(String url) {
// 根据系统来添加不同的驱动路径
String os = System.getProperty("os.name");
if (StrUtil.containsIgnoreCase(os, ArmConstant.WINDOWS)) {
System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
} else {
// 只考虑Linux环境,需要下载对应版本的驱动后放置在绝对路径/usr/bin目录下
System.setProperty("webdriver.chrome.driver", "/usr/bin/chromedriver");
}
try {
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
options.addArguments("--disable-gpu");
options.addArguments("--no-sandbox");
ChromeDriver driver = new ChromeDriver(options);
driver.manage().window().maximize();
driver.get(url);
String jsHeight = "return document.body.clientHeight";
long height = (long) driver.executeScript(jsHeight);
int k = 1;
int size = 500;
while (k * size < height) {
String jsMove = String.format("window.scrollTo(0,%s)", k * 500);
driver.executeScript(jsMove);
Thread.sleep(100);
height = (long) driver.executeScript(jsHeight);
k += 1;
}
// 通过执行脚本解决Selenium截图不全问题
long maxWidth = (long) driver.executeScript(
"return Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);");
long maxHeight = (long) driver.executeScript(
"return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);");
Dimension targetSize = new Dimension((int)maxWidth, (int)maxHeight);
driver.manage().window().setSize(targetSize);
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String strTime = sdf.format(date);
File img = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(img, new File(strTime + ".png"));
} catch (Exception e) {
e.printStackTrace();
}
}
问题
部分可以打开的网站截图失败,显示为白屏或者黑屏,如:
https://www.nifa.org.cn/nifa/2955675/2955761/2974440/index.html
截图效果:
诸般尝试,都告以失败。
想到之前手动使用FireShot插件实现网页截图。FireShot可以说是Chrome浏览器必备插件,参考关于Chrome浏览器的一些使用技巧。
而Selenium是支持添加插件执行自动化测试。想当然以为options
是通过addExtensions()
方法来添加插件,下面代码里面File目录可以有两种方式查询得知:
- 通过使用search everything全局搜索FireShot
- 打开
chrome://extensions/
,搜索FireShot,得到chrome://extensions/?id=mcbpblocgmgfnpjjppndjkmgjaogfceg
,然后去Chrome安装盘定位,得到目录,需要对Chrome的安装目录有较深理解:
options.addExtensions(new File("C:\\Users\\cheng\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Extensions\\mcbpblocgmgfnpjjppndjkmgjaogfceg\\0.99.1_0"));
结果一直报错:
java.lang.IllegalArgumentException: C:\Users\cheng\AppData\Local\Google\Chrome\User Data\Default\Extensions\mcbpblocgmgfnpjjppndjkmgjaogfceg\0.99.1_0 is a directory
实际上,Selenium添加插件有两种方式:
使用离线插件形式
必须通过addExtensions()
方法,指向本地已经下载的离线插件:
options.addExtensions(new File("D:\\迅雷下载\\FireShot\\FireShot.crx"));
ChromeDriver driver = new ChromeDriver(options);
注意,使用离线版本的插件之前,可以先校验一下插件的版本和自己当前安装的Chrome版本是否适配,地址栏打开chrome://extensions
,然后把下载的.crx
文件拖进来,如果出现下面的报错,说明版本不适配:
事实上,通过代码也可以发现版本不适配的问题:
SessionNotCreatedException: session not created: cannot process extension #1
from unknown error: CRX verification failed to parse extension header. Chrome supports only CRX3 format. Does the extension need to be updated?
下载一个更新版本的插件:
options.addExtensions(new File("D:\\迅雷下载\\FireShot_0.98.97.2_chrome.zzzmh.cn.crx"));
报错:
org.openqa.selenium.WebDriverException: unknown error: failed to wait for extension background page to load: chrome-extension://mcbpblocgmgfnpjjppndjkmgjaogfceg/_generated_background_page.html
from unknown error: page could not be found: chrome-extension://mcbpblocgmgfnpjjppndjkmgjaogfceg/_generated_background_page.html
上面报错信息里面mcbpblocgmgfnpjjppndjkmgjaogfceg
正好就是我Chrome安装的FireShot唯一ID。
怎么就失败呢?
- 禁用已经安装并启用的插件:
重试,失败。 - 删除本地文件夹
mcbpblocgmgfnpjjppndjkmgjaogfceg
,重试失败。 - 看到插件页有一个查看试图—背景页链接:
打开之后:
右键,另存为,放到本地目录C:\\Users\\cheng\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Extensions\\mcbpblocgmgfnpjjppndjkmgjaogfceg\\0.99.1_0
下面,重试,依旧不行。
Chrome无界面浏览模式与自定义插件加载问题,该篇文章指出两种是不兼容的,没有很好的解决方法。
既然如此,那去掉options.addArguments("--headless");
这一行参数配置,不报错。
但是截图依然失败。。。
百度及google,给出的一个值得尝试的stackoverflow-方案:弃用Chrome,使用Firefox。
加载本地已经安装的插件
必须通过addArguments()
方法,来加载指定的插件:
options.addArguments("load-extension=C:\\Users\\cheng\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Extensions\\mcbpblocgmgfnpjjppndjkmgjaogfceg\\0.99.1_0");
HTML页面截图成功。Wait?
问题
这种方式,怎么适用于Linux系统??