SeleniumChromeDriver截图标记指定元素的方法

编程

phantomjs 是无头浏览器的代表,可以截全屏的图,对于标记元素来说是很简单的;不过最新的 Selenium 版本表示不再支持;所以只能使用其他的代理品; 正好 chromeFirefox 等都推出无头模式,这里就使用 ChromeDriver 作为演示

ChromeDriver 通过设置 setHeadless(true) 既可开启无头模式

设置 ChromeDirver 必要的参数

//-------------------------

// 该方法有同事提供 -> 滑稽脸

//-------------------------

private static ChromeOptions initWebOption(String proxy) {

ChromeOptions chromeOptions = new ChromeOptions();

// 开启无头模式

chromeOptions.setHeadless(true);

//基础参数设置

chromeOptions.addArguments("--silent");

chromeOptions.addArguments("--no-sandbox");

chromeOptions.addArguments("--disable-gpu");

chromeOptions.addArguments("--disable-dev-shm-usage");

chromeOptions.addArguments("--ignore-certificate-errors");

chromeOptions.addArguments("--allow-running-insecure-content");

//优化参数设置

chromeOptions.addArguments("--incognito");

chromeOptions.addArguments("--disable-images");

chromeOptions.addArguments("--start-maximized");

chromeOptions.addArguments("--disable-plugins");

chromeOptions.addArguments("--disable-infobars");

chromeOptions.addArguments("--lang=zh_CN.UTF-8");

chromeOptions.addArguments("--disable-javascript");

chromeOptions.addArguments("--window-size=1928,1080");

//chromeOptions.addArguments("--auto-open-devtools-for-tabs");

//UserAgent

String userAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.3239.132 Safari/537.36";

chromeOptions.addArguments("--user-agent=" + userAgent);

log.info("[初始驱动参数] 正在设置驱动用户代理: {}", userAgent);

//设置加载策略

String pageLoadStrategy = "eager";

chromeOptions.setCapability("pageLoadStrategy", pageLoadStrategy);

log.info("[初始驱动参数] 正在设置驱动加载策略: {}", pageLoadStrategy);

//高级参数设置

Map<String, Object> chromePrefs = new HashMap<>();

//禁止密码保存

chromePrefs.put("credentials_enable_service", false);

chromePrefs.put("profile.password_manager_enabled", false);

//禁止网页弹窗

chromePrefs.put("profile.default_content_settings.popups", 0);

//禁止加载图片

chromePrefs.put("profile.managed_default_content_settings.images", 2);

chromeOptions.setExperimentalOption("prefs", chromePrefs);

//屏蔽控制显示

chromeOptions.setExperimentalOption("useAutomationExtension", false);

//突破网站检测

chromeOptions.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));

//网络代理设置

if (proxy == null || proxy.length() == 0) {

return chromeOptions;

}

Proxy netProxy = new Proxy();

netProxy.setHttpProxy(proxy);

chromeOptions.setProxy(netProxy);

return chromeOptions;

}

截屏并标记特定元素

 public void screenshotAndMark(

// Chrome Driver

WebDriver webDriver,

// 同一个页面需要标记的元素

List<WebElement> elements,

// 自定义截图的名称

Function<WebElement, String> nameMapping,

// 接受最后的结果

Consumer<Optional<List<ScreenshotMark>>> consumer

) {

if (webDriver == null) {

logger.warn("WebDriver is null and screenshot failed.");

if (consumer != null) {

consumer.accept(Optional.empty());

}

return;

}

if (elements == null || elements.isEmpty()) {

logger.warn("elements is empty and screenshot failed.");

if (consumer != null) {

consumer.accept(Optional.empty());

}

return;

}

// JS 脚本执行器

JavascriptExecutor executor = ((JavascriptExecutor) webDriver);

// 结果

List<ScreenshotMark> screenshotMarks = new ArrayList<>();

for (WebElement webElement : elements) {

// 元素原始位置

Point location = webElement.getLocation();

int x = location.x;

int y = location.y;

// 滚动元素到可视区域

// 并设置误差 10px

executor.executeScript("window.scrollTo(arguments[0], arguments[1])", x - 10, y - 10);

// 元素大小

Dimension size = webElement.getSize();

int width = size.getWidth();

int height = size.getHeight();

String name = nameMapping != null ? nameMapping.apply(webElement) : webElement.getText();

if (width == 0 || height == 0) {

System.out.println(name + " width eq zero or height eq zero, ignored.");

continue;

}

if (!webElement.isDisplayed()) {

System.out.println(name + " is not display, ignored.");

continue;

}

// 获取当前滚动条的位置

Object offsetYObj = executor.executeScript("return document.body.scrollTop || document.documentElement.scrollTop");

Object offsetXObj = executor.executeScript("return document.body.scrollLeft || document.documentElement.scrollLeft");

// 计算元素的偏移位置

int offsetY = 0;

int offsetX = 0;

if (offsetYObj != null) {

try {

offsetY = Integer.parseInt(offsetYObj.toString());

} catch (Exception e) {

// ignore

}

}

if (offsetXObj != null) {

try {

offsetX = Integer.parseInt(offsetXObj.toString());

} catch (Exception e) {

// ignore

}

}

WebDriver augmentedDriver = new Augmenter().augment(webDriver);

// 不同元素展示的结果不同

// 所以每一次都需要截屏

byte[] screenshotBytes = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.BYTES);

try (

ByteArrayInputStream bytes = new ByteArrayInputStream(screenshotBytes);

ByteArrayOutputStream result = new ByteArrayOutputStream()

) {

// 转换为图片

BufferedImage screenshot = ImageIO.read(bytes);

// 画笔

Graphics2D graphics = screenshot.createGraphics();

// 设置“抗锯齿”的属性

graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

// 画笔颜色

graphics.setColor(Color.RED);

// 画笔粗细

graphics.setStroke(new BasicStroke(4f));

// 绘制矩形标记

graphics.drawRect(x - offsetX, y - offsetY, width, height);

// 输出

ImageIO.write(screenshot, "PNG", result);

byte[] screenshotMarkBytes = result.toByteArray();

screenshotMarks.add(new ScreenshotMark(name, screenshotMarkBytes, (long) screenshotMarkBytes.length));

} catch (IOException e) {

System.err.println(name + " "+e.getMessage());

}

}

if (consumer != null) consumer.accept(Optional.of(screenshotMarks));

}

ScreenshotMark 对象

public class ScreenshotMark {

private String name;

private byte[] bytes;

private Long size;

public ScreenshotMark() {

}

public ScreenshotMark(String name, byte[] bytes, Long size) {

this.name = name;

this.bytes = bytes;

this.size = size;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public byte[] getBytes() {

return bytes;

}

public void setBytes(byte[] bytes) {

this.bytes = bytes;

}

public Long getSize() {

return size;

}

public void setSize(Long size) {

this.size = size;

}

}

测试

public static void main(String[] args) throws IOException {

// 设置驱动路径环境变量

// 必须是全路径

System.setProperty("webdriver.chrome.driver", "<path>/chromedriver.exe");

WebDriver webDriver = null;

try {

ChromeOptions options = initWebOption("");

webDriver = new ChromeDriver(options);

webDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

webDriver.manage().window().maximize();

webDriver.get("https://www.baidu.com");

long timeout = 15000;

webDriver.manage().window().setSize(new Dimension(1920, 1080));

webDriver.manage().timeouts().pageLoadTimeout(timeout, TimeUnit.MILLISECONDS);

webDriver.manage().timeouts().setScriptTimeout(timeout, TimeUnit.MILLISECONDS);

webDriver.manage().timeouts().implicitlyWait(timeout, TimeUnit.MILLISECONDS);

System.out.println("打开驱动实例成功...");

// 获取所有的a标签,并标记

List<WebElement> webElements = webDriver.findElements(By.xpath("//a"));

ScreenshotServiceImpl screenshotService = new ScreenshotServiceImpl();

screenshotService.screenshotAndMark(webDriver, webElements, WebElement::getText, optional -> {

// 该处为了演示,实际可以拿到bytes[] 上传到服务器,或其他地方

if (optional.isPresent()) {

for (ScreenshotMark screenshotMark : optional.get()) {

String name = screenshotMark.getName();

name = name == null || name.length() == 0 ? Math.random() + "" : name;

try (ByteArrayInputStream bytes = new ByteArrayInputStream(screenshotMark.getBytes())) {

BufferedImage image = ImageIO.read(bytes);

ImageIO.write(image, "png", new File("<path>/" + name + ".png"));

} catch (IOException e) {

System.err.println("error finally:" + e.getMessage());

}

}

}

});

} catch (Exception e) {

e.printStackTrace();

} finally {

System.out.println("completed finally.");

if (webDriver != null) webDriver.quit();

}

}

备注

  • ChromeDriverclose/quit 区别见 Java+Selenium3方法篇20-浏览器退出quit和close的区别
  • 正常情况下 ChromeDiver 无法截全屏的图
  • 执行 JS 脚本,通过 return 获取返回值

原文链接 IT浪子の博客 > Selenium ChromeDriver 截图标记指定元素的方法

以上是 SeleniumChromeDriver截图标记指定元素的方法 的全部内容, 来源链接: utcz.com/z/515870.html

回到顶部