Java 实现通过网址URL截图
1.DjNativeSwing方式 (不好用)
实操 DjNativeSwing 方式 的现象
1.截图效果(非百度网页):有图片,排版正常,但是部分样式丢失(输入框的文字掉下去了)
2.main 方法使用的里面没问题 ,但是springboot项目去启动以后,该方式触发报错
需要在启动类,关闭无头模式
3.本地项目成功实现以后
部署linux系统后,我这一块还是出现了 与“awt .headless”相关的错误
(1)Can’t connect to ll window server using ‘0.g’ as the value of the DISPLAY variable.
要我去配置
JAVA OPTS=-Djava.awt.headless=true
可我本地程序需要关闭才能用,怎么linux上面又让我开启
想了想是不是,打包上我改成本地要开启,结果发布上linux还是不行
耗费太长时间,想了想,截出来的图是有瑕疵问题,索性直接放弃了该方式
参考文章
(1)https://codeleading.com/article/3074321735/
(2)https://blog.51cto.com/binghe001/5243790
(3)https://www.cnblogs.com/lsy-blogs/p/7700564.html
(4)https://blog.csdn.net/ljj9oo9/article/details/8771670
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>DJNativeSwing</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>DJNativeSwing-SWT</artifactId>
<version>1.0.0</version>
</dependency>
<!--win64-->
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
<version>4.3</version>
</dependency>
<!--linux-->
<!-- <dependency>-->
<!-- <groupId>org.eclipse.swt</groupId>-->
<!-- <artifactId>org.eclipse.swt.gtk.linux.x86_64</artifactId>-->
<!-- <version>4.3</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
1.首先在springboot启动页上重写方法(配置关闭无头模式):
@SpringBootApplication
public class DjnativeswingApplication {
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(DjnativeswingApplication.class);
ApplicationContext applicationContext = builder.headless(false).run(args);
applicationContext.getBean(调用.class);
// SpringApplication.run(DjnativeswingApplication.class, args);
}
}
2.写一个工具类:
import chrriis.dj.nativeswing.swtimpl.NativeComponent;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserAdapter;
import chrriis.dj.nativeswing.swtimpl.components.WebBrowserEvent;
import com.linewell.gov.hoox.utils.log.LogUtil;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
/**
* Created with CosmosRay
* 条件:需要给启动类,关闭无头模式,
* 缺陷:部分网址,截图样式部分还是有问题
* @author CosmosRay
* @date 2019/5/22
* Function:
*/
public class DjNativeSwingUtil extends JPanel {
// 行分隔符
final static public String LS = System.getProperty("line.separator", "\n");
// 文件分割符
final static public String FS = System.getProperty("file.separator", "\\");
// 以javascript脚本获得网页全屏后大小
private static final long serialVersionUID = 1L;
private static final StringBuffer jsDimension;
static {
jsDimension = new StringBuffer();
jsDimension.append("var width = 0;").append(LS);
jsDimension.append("var height = 0;").append(LS);
jsDimension.append("if(document.documentElement) {").append(LS);
jsDimension.append(" width = Math.max(width, document.documentElement.scrollWidth);").append(LS);
jsDimension.append(" height = Math.max(height, document.documentElement.scrollHeight);").append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("if(self.innerWidth) {").append(LS);
jsDimension.append(" width = Math.max(width, self.innerWidth);").append(LS);
jsDimension.append(" height = Math.max(height, self.innerHeight);").append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("if(document.body.scrollWidth) {").append(LS);
jsDimension.append(" width = Math.max(width, document.body.scrollWidth);").append(LS);
jsDimension.append(" height = Math.max(height, document.body.scrollHeight);").append(LS);
jsDimension.append("}").append(LS);
jsDimension.append("return width + ':' + height;");
}
public DjNativeSwingUtil( String url, String token, String fileName, int maxWidth, int maxHeight) {
super(new BorderLayout());
//面板
LogUtil.info("DjNativeSwingUtil-面板进入");
JPanel webBrowserPanel = new JPanel(new BorderLayout());
final JWebBrowser webBrowser = new JWebBrowser(null);
webBrowser.setBarsVisible(false);
//设置cooker
webBrowser.setCookie(url, "token=" + token);
webBrowser.navigate(url);
webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
add(webBrowserPanel, BorderLayout.CENTER);
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 4));
webBrowser.addWebBrowserListener(new WebBrowserAdapter() {
// 监听加载进度
@Override
public void loadingProgressChanged(WebBrowserEvent e) {
// 当加载完毕时
if (e.getWebBrowser().getLoadingProgress() == 100) {
/*睡眠3秒钟,等待页面请求完毕再截取图片信息
* 如果不延时,则图片等可能没有时间下载显示
* 具体的秒数需要根据网速等调整
* */
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
String result = (String) webBrowser.executeJavascriptWithResult(jsDimension.toString());
int index = result == null ? -1 : result.indexOf(":");
NativeComponent nativeComponent = webBrowser.getNativeComponent();
Dimension originalSize = nativeComponent.getSize();
Dimension imageSize = new Dimension(Integer.parseInt(result.substring(0, index)), Integer.parseInt(result
.substring(index + 1)));
// imageSize.width = Math.max(originalSize.width, imageSize.width + 50);
// imageSize.height = Math.max(originalSize.height, imageSize.height + 50);
imageSize.width = maxWidth;
imageSize.height = maxHeight;
nativeComponent.setSize(imageSize);
BufferedImage image = new BufferedImage(imageSize.width,
imageSize.height, BufferedImage.TYPE_INT_RGB);
nativeComponent.paintComponent(image);
nativeComponent.setSize(originalSize);
try {
// 输出图像
System.out.println(fileName);
ImageIO.write(image, "png", new File(fileName));
} catch (IOException ex) {
ex.printStackTrace();
}
// 退出操作 (会把整个springboot项目都杀掉)
//System.exit(0);
}
}
}
);
add(panel, BorderLayout.SOUTH);
}
public static void main(String[] args) {
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// SWT组件转Swing组件,不初始化父窗体将无法启动webBrowser
javax.swing.JFrame frame = new javax.swing.JFrame("以DJ组件保存指定网页截图");
// 加载google,最大保存为640x480的截图
//实际项目中传入URL参数,根据不同参数截取不同网页快照,保存地址也可以在构造器中多设置一个参数,保存到指定目录
frame.getContentPane().add(new DjNativeSwingUtil(
"https://www.baidu.com",
null,
"D:\\" + System.currentTimeMillis() + ".png",
1800, 1300
), BorderLayout.CENTER);
frame.setSize(2200, 1800);
// 仅初始化,但不显示
frame.invalidate();
frame.pack();
//隐藏并释放内存,并不一定结束整个应用程序
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//将窗口隐藏(但窗口的相关资源仍然存在)
frame.setVisible(false);
}
});
NativeInterface.runEventPump();
}
}
- 调用工具类的类:
@Configuration
public class TestController {
public static boolean printUrlScreen2jpg(final String file, final String url, final int width, final int height) {
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String withResult = "var width = " + width + ";var height = " + height + ";return width +':' + height;";
if (width == 0 || height == 0)
withResult = DjNativeSwing.getScreenWidthHeight();
JFrame frame = new JFrame("网页截图");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 加载指定页面,最大保存为640x480的截图
frame.getContentPane().add(new DjNativeSwing(file, url, withResult), BorderLayout.CENTER);
frame.setSize(640, 800);
// 仅初始化,但不显示
frame.invalidate();
frame.pack();
frame.setVisible(false);
}
});
NativeInterface.runEventPump();
return true;
}
}
如果 “非main方法” 调用 出现线程问题,需要用线程包裹调用
@Configuration
public class TestController {
public static int runEventPumpValue = 0;
public static boolean printUrlScreen2jpg(final String file, final String url, final int width, final int height) {
Thread thread = new Thread(() -> {
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String withResult = "var width = " + width + ";var height = " + height + ";return width +':' + height;";
if (width == 0 || height == 0)
withResult = DjNativeSwing.getScreenWidthHeight();
JFrame frame = new JFrame("网页截图");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 加载指定页面,最大保存为640x480的截图
frame.getContentPane().add(new DjNativeSwing(file, url, withResult), BorderLayout.CENTER);
frame.setSize(640, 800);
// 仅初始化,但不显示
frame.invalidate();
frame.pack();
frame.setVisible(false);
}
});
//如果在for循化调用触发该方法,runEventPump()是只能被调起一次的
if (runEventPumpValue == 0) {
runEventPumpValue += 1;
NativeInterface.runEventPump();
}
});
thread.start();
return true;
}
}
4.接口调用:
@RequestMapping(value = "/htmltest", produces = "application/json;charset=UTF-8")
@ResponseBody
public String htmlGenerator() throws Exception{
TestController.printUrlScreen2jpg("G:/网页截图.png", "G:/index.html", 1000, 1300);
return null;
}
2.phantomjs方式 (截图还是有瑕疵)
实操 phantomjs 方式 的现象
截图效果(非百度网页):有图片,排版稍微有点问题,样式正常,但是有些文字居然少了一截
虽然不用搞什么“无头”模式之类的了,但是我看到本地截图效果还是选择放弃使用这种方式
PlantomJs是一个基于javascript的webkit内核无头浏览器 也就是没有显示界面的浏览器,你可以在基于 webkit 浏览器做的事情,它都能做到。PlantomJs提供了如 CSS 选择器、DOM操作、JSON、HTML5、Canvas、SVG 等。
PhantomJS 的用处很广泛,如网络监控、网页截屏、页面访问自动化、无需浏览器的 Web 测试等,这里只用到网页截屏。
PlantomJs可以通过官网下载http://phantomjs.org/download.html,
也可以通过(只有windows版本):https://pan.baidu.com/s/1EVX1RPX7gY0rGvEI6OHcwg 密码:brb4 下载;解压后可以看到
参考链接
(1)Java实现网页截屏功能(基于phantomJs)https://www.cnblogs.com/han108/p/9216583.html#:~:text=var%20page%20%3D%20require%20%28%27webpage%27%29.create%20%28%29%2C%20system%20%3D,%28output%29%3B%20phantom.exit%20%28%29%3B%20%7D%2C%20200%29%3B%20%7D%20%7D%29%3B%20%7D
(2)完美解决java截图网页并保存到数据库中预览
https://blog.csdn.net/qq_43665446/article/details/129312799?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-129312799-blog-37992055.235%5Ev38%5Epc_relevant_anti_vip&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-129312799-blog-37992055.235%5Ev38%5Epc_relevant_anti_vip&utm_relevant_index=4
(3)phantom添加cookie
https://www.ngui.cc/el/2578032.html?action=onClick
(4)使用phantomjs对网页截图
https://blog.csdn.net/FreemanZhao/article/details/77498749
(5)selenium+phantomjs截长图踩坑
https://blog.csdn.net/u014307117/article/details/108187245
下载好后的“D:\phantomjs-2.1.1-windows”文件夹里面的 “examples”文件夹里面有个rasterize.js文件,用下面这个内容替代掉即可
rasterize.js
如果要加cookie,要特别注意”domain”这个值是必传且不能随便乱传,和你要截图的地址相关,不然会报错的
var page = require('webpage').create(),
system = require('system'),
address, output, size;
//可以带cookie
//var flag = phantom.addCookie({
// "domain": ".baidu.com" ,
// "expires": "Fri, 01 Jan 2038 00:00:00 GMT",
// "expiry": 2145916800,
// "httponly": false,
// "name": "token",
// "path": "/",
// "secure": false,
// "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJud19kemdkIiwiRXhwaXJlIjoiMjAyMy0wOC0xMCAxNDoyMzo0NyJ9.InsFJkcXI6C57r-1Oqb7PMn-OcP9k0W5lf1K896EasY"
//});
if (system.args.length < 3 || system.args.length > 5) {
phantom.exit(1);
} else {
address = system.args[1];//传入url地址
output = system.args[2];//输出图片的地址
page.viewportSize = { width: 800, height: 1800 };//自定义定义宽高
if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
size = system.args[3].split('*');
page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
: { format: system.args[3], orientation: 'portrait', margin: '1cm' };
} else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
size = system.args[3].split('*');
if (size.length === 2) {
pageWidth = parseInt(size[0], 10);
pageHeight = parseInt(size[1], 10);
page.viewportSize = { width: pageWidth, height: pageHeight };
page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
} else {
console.log("size:", system.args[3]);
pageWidth = parseInt(system.args[3], 10);
pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
console.log ("pageHeight:",pageHeight);
page.viewportSize = { width: pageWidth, height: pageHeight };
}
}
if (system.args.length > 4) {
page.zoomFactor = system.args[4];
}
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit(1);
} else {
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 3000);
}
});
}
address = system.args[1];//传入url地址
output = system.args[2];//输出图片的地址
page.viewportSize = { width: 2000, height: 1300 };//自定义定义宽高
后端代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
/**
* @Description:根据网页地址转换成图片
* @Author: admin
* 条件:需要插件及js脚本
* 缺陷:部分网址,截图样式部分还是有问题
* @CreateDate: 2018年6月22日
*/
public class PhantomTools {
private static String tempPath = "D:/temp/img";// 图片保存目录
private static String BLANK = " ";
// 下面内容可以在配置文件中配置
private static String binPath = "D:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe";// 插件引入地址
private static String jsPath = "D:\\phantomjs-2.1.1-windows\\examples\\rasterize.js";// js引入地址
private static String cookie = "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiJud19kemdkIiwiRXhwaXJlIjoiMjAyMy0wOC0xMCAxMzoxMTozMCJ9.IbO0oobfU5GTURuTnc7NyfnbMN-lkXalNEafDPXyzWE";// token
// 执行cmd命令
public static String cmd(String imgagePath, String url) {
return binPath + BLANK + jsPath + BLANK + url + BLANK + imgagePath;
}
//关闭命令
public static void close(Process process, BufferedReader bufferedReader) throws IOException {
if (bufferedReader != null) {
bufferedReader.close();
}
if (process != null) {
process.destroy();
process = null;
}
}
/**
* @param
* @param url
* @throws IOException
*/
public static void printUrlScreen2jpg(String url) throws IOException{
String imgagePath = tempPath+"/"+System.currentTimeMillis()+".png";//图片路径
//Java中使用Runtime和Process类运行外部程序
Process process = Runtime.getRuntime().exec(cmd(imgagePath,url));
InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String tmp = "";
while ((tmp = reader.readLine()) != null) {
close(process,reader);
}
System.out.println("success");
}
public static void main(String[] args) throws IOException {
String url = "https://www.baidu.com/";//以百度网站首页为例
PhantomTools.printUrlScreen2jpg(url);
}
}
3.selenium方式 (满意,成功实现)
实操 selenium 方式 的现象
截图效果(非百度网页):有图片,排版没问题,样式没问题
经测试决定使用它了
参考链接
(1)Java 实现通过网址URL截取整个网页的长图并保存(遇到的各种坑)
https://blog.csdn.net/Mli_Mi/article/details/116259669
(2)selenium+phantomjs截长图踩坑
https://blog.csdn.net/u014307117/article/details/108187245
(3)如何在linux系统执行java项目+selenium
https://blog.csdn.net/weixin_42736075/article/details/113444305?spm=1001.2014.3001.5506
(4)java WebDriver + selenium 调用 谷歌驱动 chromedriver 实现 在 liunx 环境下(这个可细看)
https://blog.51cto.com/u_15739621/5682989
(5)【Selenium & Other】使用quit()无法关闭窗口 & 一键杀死进程 (这个可细看,循环调用肯定会出在的问题)
https://frica.blog.csdn.net/article/details/126717174?spm=1001.2101.3001.6650.14&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-14-126717174-blog-106362343.235%5Ev38%5Epc_relevant_anti_vip_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-14-126717174-blog-106362343.235%5Ev38%5Epc_relevant_anti_vip_base&utm_relevant_index=18
(6)解决java使用Runtime.exec执行linux命令不成功问题
http://bcxw.net/article/757.html
maven 引入
1.请注意自己的项目里面是不是存在其他的“com.google.guava”版本,如果有请排除(全部排除),不然会出现所谓的
“com.google.common.util.concurrent.SimpleTimeLimiter.create(Ljava/util/concurrent/ExecutorService;)Lcom/google/common/util/concurrent/SimpleTimeLimiter;”
2.以下我选择的依赖版本是和后面的“浏览器版本”及“驱动版本”息息相关,
高版本亦或者低版本都可能会出现运行失败的现象
<!--自动化测试工具,需要去其他网址下第三方包-->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
下载相关浏览器chrome
我这边下载的是98.0.4758.102版本的浏览器(最新版本不容易配置)
(windows)https://www.chromedownloads.net/chrome64win/
windows会自己更新,需要自己去禁止更新,不然测着测着,浏览器升级了(除非你旧版本打开以后,就不要关闭),导致代码报错
(linux)https://www.chromedownloads.net/chrome64linux/
linux系统不会自动更新的,不要担心
下载相关浏览器chromedriver驱动
我这边下载的也是98.0.4758.102版本
https://registry.npmmirror.com/binary.html?path=chromedriver/98.0.4758.102/
liunx服务器上面的安装相应的浏览器的执行命令
先cmd到你创建的目录下面,把linux版本chrome浏览器安装包移到下面,以上链接下载下来解压以后里面有两个版本的(rpm包和deb包)
rpm包相对来说版本不是最新的,但是比较稳定;
而deb包则相对来说版本比较新,一般某个新软件出来说可能有deb包,但是使用过程中容易引起bugs。
所以只留rpm包即可,放到linux的上面去
执行命令
cd到你放那个包的位置,然后执行安装命令
yum install 98.0.4758.102-google-chrome-stable_current_x86_64.rpm
后面会出现选择,输入“y” 确认安装即可
对于驱动文件也需要执行一下“可执行、读取”的命令
cd /usr/local/xxxx/ChromeDriver/chromedriver_linux64
chmod a+x chromedriver
再下载字体包,如果部分字体还是有问题,就需要去找字体包了
(我这边都是正常的字体,就没有去找其他的字体包了)
yum install mesa-libOSMesa-devel gnu-free-sans-fonts wqy-zenhei-fonts
后端代码
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.epoint.third.apache.commons.io.FileUtils;
import com.linewell.gov.hoox.utils.log.LogUtil;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* 条件:需要谷歌浏览器版本和驱动版本一张
*/
public class SeleniumTools {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
Timestamp now1 = new Timestamp(startTime);
System.out.println("now1:" + now1);
for (int i = 0; i < 3; i++) {
try {
guge("D:/guge/img"+"/"+System.currentTimeMillis()+".png",
"https://mpage.taobao.com/hd/download.html",
"123");
} catch (Exception e) {
e.printStackTrace();
}
}
long between = DateUtil.between(new Date(startTime), new Date(), DateUnit.SECOND);
System.out.println("相差秒"+between);
System.out.println("相差分钟"+between/60);
}
//解决如下: 模拟浏览器滚动滚动条 解决懒加载问题
public static void guge(String hzdtpwzPath, String url, String nhhzdtoken) throws IOException {
LogUtil.info("=====guge=========");
LogUtil.info(hzdtpwzPath);
LogUtil.info(url);
LogUtil.info(nhhzdtoken);
// 根据系统来添加不同的驱动路径
String os = System.getProperty("os.name");
LogUtil.info(os);
String driverPath ="";
if (StrUtil.containsIgnoreCase(os, "Windows")) {//微软系统
driverPath+="D:\\chromedriver_win32 (98.0.4758.102)\\chromedriver.exe";
//程序执行,核心代码
processCMD("taskkill /F /im chromedriver.exe",1);
} else {//linux系统
driverPath+="/usr/local/xxxx/ChromeDriver/chromedriver_linux64/chromedriver";
//程序执行,核心代码
processCMD("ps -ef | grep Chrome | grep -v grep | awk '{print \"kill -9 \"$2}' | sh",2);
}
//频繁的启动关闭,会增加一个比较明显的延时导致浏览器进程不被关闭的情况发生,
// 为了避免这一状况我们可以通过ChromeDriverService来控制ChromeDriver进程的生死,
// 达到用完就关闭的效果避免进程占用情况出现(Running the server in a child process)
ChromeDriverService service =new ChromeDriverService.Builder().usingDriverExecutable(new File(driverPath)).usingAnyFreePort().build(); // 新建service 方便后面关闭chromedriver
service.start(); // 开启服务
ChromeOptions options = new ChromeOptions();
//ssl证书支持
options.setCapability("acceptSslCerts", true);
//截屏支持
options.setCapability("takesScreenshot", true);
//css搜索支持
options.setCapability("cssSelectorsEnabled", true);
//设置浏览器参数
// 设置无轨 开发时还是不要加,可以看到浏览器效果
options.addArguments("--headless");
options.addArguments("--no-sandbox");
options.addArguments("--disable-gpu");
options.addArguments("--disable-dev-shm-usage");
//处理僵尸进程
options.addArguments("--no-zygote");
//设置无头模式,一定要设置headless,否则只能截出电脑屏幕大小的图!!!
options.setHeadless(true);
WebDriver driver = new ChromeDriver(service,options);
//设置超时,避免有些内容加载过慢导致截不到图
driver.manage().timeouts().pageLoadTimeout(1, TimeUnit.MINUTES);
driver.manage().timeouts().implicitlyWait(1, TimeUnit.MINUTES);
driver.manage().timeouts().setScriptTimeout(1, TimeUnit.MINUTES);
try {
//设置需要访问的地址
driver.get(url);
//先登录,再设置cookies
Cookie c1 = new Cookie("token", nhhzdtoken);
driver.manage().addCookie(c1);
//设置需要访问的地址
driver.get(url);
//获取高度和宽度一定要在设置URL之后,不然会导致获取不到页面真实的宽高;
Long width = (Long) ((ChromeDriver) driver).executeScript("return document.documentElement.scrollWidth");
Long height = (Long) ((ChromeDriver) driver).executeScript("return document.documentElement.scrollHeight");
LogUtil.info("宽带:" + width);
LogUtil.info("高度:" + height);
//这里需要模拟滑动,有些是滑动的时候才加在的
long temp_height = 0;
while (true) {
//每次滚动500个像素,因为懒加载所以每次等待2S 具体时间可以根据具体业务场景去设置
Thread.sleep(1000);
((ChromeDriver) driver).executeScript("window.scrollBy(0,500)");
temp_height += 500;
if (temp_height >= height) {
break;
}
}
//设置窗口宽高,设置后才能截全
driver.manage().window().setSize(new Dimension(width.intValue()+1120, height.intValue()+303));
//设置截图文件保存的路径
String screenshotPath = hzdtpwzPath;
File srcFile = ((ChromeDriver) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File(screenshotPath));
LogUtil.info("设置浏览器截图文件保存的路径:" + screenshotPath);
} catch (Exception e) {
throw new RuntimeException("截图失败", e);
} finally {
//close仅仅关闭了当前页面,并未关闭chrome。
//使用quit则会真正退出chrome,结束进程。
//两者一起使用,才能避免频繁的启动关闭出现的卡住现象(重点)
driver.close();
driver.quit();
service.stop();
}
}
//直接杀进程
public static int processCMD(String commend,int type) {
//正常写 linux命令即可 、比如:mkdir xx/touch b.txt/sh start.sh/sh stop.sh
int i = 0;
Process process =null;
//程序执行,核心代码
try {
if(type==1){
//cmd /c dir 是执行完dir命令后关闭命令窗口。看需调整
String[] cmd = new String[]{"cmd","/c",commend};
process = Runtime.getRuntime().exec(cmd);
//也可以直接使用 process = Runtime.getRuntime().exec(commend)
}else{
//要想保证linux环境下命令能够执行成功,必须使用String[]
String[] cmd = new String[]{"sh","-c",commend};
process = Runtime.getRuntime().exec(cmd);
}
i = process.waitFor();
System.out.println("执行kill进程命令结果:" + i);
} catch (Exception e) {
e.printStackTrace();
}
return i;
}
//通常,安全编码规范中都会指出:使用Process.waitFor()的时候,
//可能导致进程阻塞,甚至死锁。
//使用java代码执行shell脚本,执行后会发现Java进程和Shell进程都会挂起,无法结束。
public static int processCMD2(String commend) {
//正常写 linux命令即可 、比如:mkdir xx/touch b.txt/sh start.sh/sh stop.sh
int i = 0;
Process process = null;
try {
process = Runtime.getRuntime().exec(commend);
//获取进程的标准输入流
final InputStream is1 = process.getInputStream();
//获取进城的错误流
final InputStream is2 = process.getErrorStream();
//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
new Thread(() -> {
BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
try {
String line1 = null;
while ((line1 = br1.readLine()) != null) {
if (line1 != null) {
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
try {
String line2 = null;
while ((line2 = br2.readLine()) != null) {
if (line2 != null) {
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
//可能导致进程阻塞,甚至死锁
i = process.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
try {
process.getErrorStream().close();
process.getInputStream().close();
process.getOutputStream().close();
} catch (Exception ee) {
}
}
LogUtil.info("CMD2-执行kill进程命令:" + commend);
System.out.println("CMD2-执行kill进程命令:" + commend);
LogUtil.info("CMD2-执行kill进程命令结果:" + i);
System.out.println("CMD2-执行kill进程命令结果:" + i);
return i;
}
}
大量循化调用会导致chromedriver无法关闭,程序就无法截图了,该问题我通过
driver.close()和driver.quit()同时使用,短时间没问题,长时间还是有问题,
最后又加上了kill进程的处理
明明开始好好的,突然发现用不了,可能是程序进程未正常关闭(linux系统)
需要kill -9 进程id
//查看webdriver进程,然后杀掉
ps -aux | grep webdriver
//查看chromedriver进程,然后杀掉
ps -axu | grep chromedriver
大功搞成了