【终极方案】java通过Selenium调用chrome实现html转图片

作者: ʘᴗʘ发布时间:2023-01-29 17:19 浏览量:1027 点赞:862 售价:0

需求背景

本站部分代码在没有登录的时候,为了防止爬虫抄袭,代码文本是以图片展示的。这个需求就导致我们需要一个将HTML转为图片的工具。

最早的时候,我们采用了网上开源的html2image,使用了一段时间后发现了如下几个问题:

  • 这个开源项目实在是太老了,已经很多很多年不更新了。
  • 兼容性很差。由于长时间不更新,一些新的css样式等,是完全无法正常显示的。
  • 没人维护,导致有很多安全性很严重的BUG。

基于上面的这些痛点,我们一直在积极的寻找替代方案。在看了很多方案后,发现都没办法完美的解决上面的问题。其中最难的就是,如何完美的显示各种复杂的HTML网页?你会发现,真正能做到持续兼容各种HTML和CSS、JS的,只有我们常用的浏览器。因为这个工作量巨大,只能交给大厂来做。目前开源的HTML转图片的方案,随着时间推移,大概率都会出问题。

如何一劳永逸的解决HTML转图片Image的问题呢?

解决办法

既然只有浏览器能完美的展示HTML,那我们就用浏览器来显示HTML,然后调用浏览器的API截图。这样就实现了HTML转图片的需求了。

我们采用的技术方案是java+selenium+chrome+chromedriver,这套技术组合其实更多的是用在自动化测试里,主要用于编写程序,对网页进行点击等自动化的操作。经过测试,这套方案,完美的解决了前面提出的需求和问题。

小缺陷:和传统方案不同,因为该方案需要浏览器支持,所以服务器上安装了chrome,算是一点小缺陷吧。

代码展示

由于不确定本文介绍的方案读者是否需要,这里的代码只展示核心部分,如果你想要完整的代码,可以联系作者。

package com.coderbbb.blogv2.utils;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverLogLevel;
import org.openqa.selenium.chrome.ChromeOptions;

import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class SeleniumUtil {

    public static WebDriver webDriver;

    public static ConcurrentHashMap<String, String> HTML_IMAGE_CACHE = new ConcurrentHashMap<>();

    public synchronized static void init() {
        if (webDriver == null) {
            System.setProperty("webdriver.chrome.driver", "D:\\software\\chrome-driver\\chromedriver.exe");

            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.setLogLevel(ChromeDriverLogLevel.WARNING);

            // 设置后台静默模式启动浏览器
            chromeOptions.setHeadless(true);
            chromeOptions.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));

            Map<String, Object> prefs = new HashMap<>();
            prefs.put("credentials_enable_service", false);
            prefs.put("profile.password_manager_enabled", false);


//        chromeOptions.addArguments("--headless");
            chromeOptions.addArguments("--disable-blink-features");
            chromeOptions.addArguments("--disable-blink-features=AutomationControlled");
            chromeOptions.setExperimentalOption("prefs", prefs);
            chromeOptions.addArguments("--no-sandbox");
            chromeOptions.addArguments("--disable-dev-shm-usage");
            chromeOptions.addArguments("--incognito");
            chromeOptions.addArguments("--disable-gpu");
            chromeOptions.addArguments("--ignore-certificate-errors");
            chromeOptions.addArguments("--ignore-ssl-errors");
            String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36";
            userAgent = "user-agent=" + userAgent;
            chromeOptions.addArguments(userAgent);
            chromeOptions.addArguments("--start-maximized");

            webDriver = new ChromeDriver(chromeOptions);

            //设置窗口大小
            Dimension dimension = new Dimension(1000, 30);
            webDriver.manage().window().setSize(dimension);
        }
    }

    public static WebDriver getWebDriver() {
        if (webDriver == null) {
            init();
        }
        return webDriver;
    }

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

        getWebDriver().get("https://www.coderbbb.com");

        File file = ((TakesScreenshot) getWebDriver()).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(file, new File("./code2.png"));

    }


}

上面的代码中,main方法就是直接调用selenium,打开一个网页,然后截图保存。

问题回复:

  • 如何将一段HTML转化为图片?答:如果你需要将具体的一段HTML转化为图片,你可以自己写一个可以访问的网页,把这段HTML传入,再使用前面的办法截图。

  • 如果网页很长,怎么全屏截图?答:selenium使用HeadLess模式(就是不显示界面,后台静默执行)时,可以任意设置浏览器窗口大小,那么你设置浏览器高度和你的HTML网页高度一致,再截图,就能得到完整的网页截图了。这个方案最简单,不用考虑滚动条等等的问题。

  • 怎么获取HTML网页的高度?答:该问题是问题2的后续。主要是通过selenium来执行JavaScript脚本return document.documentElement.scrollHeight来获取。代码展示如下:

    //根据内容,重新设定窗口大小
    JavascriptExecutor javascriptExecutor = (JavascriptExecutor) getWebDriver();
    Long height = (Long) javascriptExecutor.executeScript("return document.documentElement.scrollHeight");
    Dimension dimension = new Dimension(1000, height.intValue());
    getWebDriver().manage().window().setSize(dimension);
    

    这段代码的作用,就是通过执行JavaScript脚本,来获取HTML网页的高度,然后根据该高度调整浏览器窗口的高度,从而实现任意高度的网页都可以完整显示,避免出现滚动条影响截图。其中,getWebDriver()是我们封装的方法,可以参考前面提到的代码。

效果展示

本站所有代码片段,都是通过该技术实现从HTML文本到图片的转化的。就拿本文来说,上面的代码图片就是该技术的效果展示。

版权声明:《【终极方案】java通过Selenium调用chrome实现html转图片》为CoderBBB作者「ʘᴗʘ」的原创文章,转载请附上原文出处链接及本声明。

原文链接:https://www.coderbbb.com/articles/72

其它推荐:

user

ʘᴗʘ

77
文章数
67043
浏览量
53259
获赞数
67.80
总收入