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目录可以有两种方式查询得知:

  1. 通过使用search everything全局搜索FireShot
  2. 打开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。

怎么就失败呢?

  1. 禁用已经安装并启用的插件:
    在这里插入图片描述
    重试,失败。
  2. 删除本地文件夹mcbpblocgmgfnpjjppndjkmgjaogfceg,重试失败。
  3. 看到插件页有一个查看试图—背景页链接:
    在这里插入图片描述
    打开之后:
    在这里插入图片描述
    右键,另存为,放到本地目录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系统??

参考

Selenium启动Chrome插件(Chrome Extensions)

posted @ 2021-06-28 15:17  johnny233  阅读(151)  评论(0编辑  收藏  举报  来源