欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java利用phantomjs进行截图实例教程

程序员文章站 2024-02-26 17:48:58
前言 最近工作中遇到一个需求,需要实现截图功能,断断续续查找资料、验证不同的实现方法终于算基本搞定了页面截图,因为中间过程曲折花费较多时间,分享出来帮助大家快速实现截图...

前言

最近工作中遇到一个需求,需要实现截图功能,断断续续查找资料、验证不同的实现方法终于算基本搞定了页面截图,因为中间过程曲折花费较多时间,分享出来帮助大家快速实现截图

为什么选用phantomjs进行截图

截图可以实现的方式有很多,比如:

  • selenium
  • htmlunit
  • html2image、、、and so on但是这些实现的截图效果都不好。selenium只能实现截屏,不能截取整个页面,而htmlunit、html2image对js的支持效果并不好,截下来的图会有很多空白。phantomjs就是万精油了,既能截取整个页面,对js支持的效果又好

plantomjs提供了如 css 选择器、dom操作、json、html5、canvas、svg 等。phantomjs 的用处很广泛,如网络监控、网页截屏、页面访问自动化、无需浏览器的 web 测试等,这里只用到网页截屏。

前期准备

安装phantomjs。mac os

brew install phantomjs

命令行的方式进行截图

安装以后我们就可以小试牛刀了

打开终端,输入以下命令:

/users/hetiantian/softwares/phantomjs/bin/phantomjs
/users/hetiantian/softwares/phantomjs/examples/rasterize.js
https://juejin.im/post/5bb24bafe51d450e4437fd96
/users/hetiantian/desktop/juejin-command.png

查看效果

java利用phantomjs进行截图实例教程

发现图片没有加载好

来看以下刚刚的命令行:

/users/hetiantian/softwares/phantomjs/bin/phantomjs:phantomjs可执行文件保存地址
/users/hetiantian/softwares/phantomjs/examples/rasterize.js:rasterize.js文件地址

这段命令可以理解为用phantomjs去运行rasterize.js文件,所以要想解决图片空白的问题我们需要去看一下rasterize.js文件。

"use strict";
var page = require('webpage').create(),
 system = require('system'),
 address, output, size, pagewidth, pageheight;

if (system.args.length < 3 || system.args.length > 5) {
 console.log('usage: rasterize.js url filename [paperwidth*paperheight|paperformat] [zoom]');
 console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "a4", "letter"');
 console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px');
 console.log('         "800px*600px" window, clipped to 800x600');
 phantom.exit(1);
} else {
 address = system.args[1];
 output = system.args[2];
 page.viewportsize = { width: 600, height: 600 };
 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();
   }, 200);
  }
 });
}

尝试一:

对page.viewportsize = { width: 600, height: 600 };产生了疑问????️

把height调大十倍,发现基本是完美截图了,但是如果页面的篇幅特别短,会发现有瑕疵,下面留有一大片空白。原因:page.viewportsize = { width: 600, height: 600 };设置的是初始打开浏览器的大小,通过增大这个值可以加载js。如果我们能拿到实际页面的大小在设置height大小,但是不,我不能。

并且不能接受预先设定一个很大的height值,比如30000,因为不能接受底下留白的效果

尝试二:

在window.settimeout方法之前加入以下代码

 page.evaluate(function(){
  scrollby(0, 18000); 
});

无奈evaluate里不能在用for循环了,前端渣渣真的不知道如何改,遂放弃

java代码方式进行截图

需要的依赖

  <dependency>
   <groupid>org.seleniumhq.selenium</groupid>
   <artifactid>selenium-java</artifactid>
   <version>2.45.0</version>
  </dependency>

  <dependency>
   <groupid>com.codeborne</groupid>
   <artifactid>phantomjsdriver</artifactid>
   <version>1.2.1</version>
   <!-- this will _always_ be behind -->
   <exclusions>
    <exclusion>
     <groupid>org.seleniumhq.selenium</groupid>
     <artifactid>selenium-java</artifactid>
    </exclusion>
    <exclusion>
     <groupid>org.seleniumhq.selenium</groupid>
     <artifactid>selenium-remote-driver</artifactid>
    </exclusion>
   </exclusions>
  </dependency>

代码实现

public class phantomjstest2 {
 public static void main(string[] args) throws interruptedexception, ioexception {
  //设置必要参数
  desiredcapabilities dcaps = new desiredcapabilities();
  //ssl证书支持
  dcaps.setcapability("acceptsslcerts", true);
  //截屏支持
  dcaps.setcapability("takesscreenshot", true);
  //css搜索支持
  dcaps.setcapability("cssselectorsenabled", true);
  //js支持
  dcaps.setjavascriptenabled(true);
  //驱动支持(第二参数表明的是你的phantomjs引擎所在的路径)
  dcaps.setcapability(phantomjsdriverservice.phantomjs_executable_path_property,
    "/users/hetiantian/softwares/phantomjs/bin/phantomjs");
  //创建*面浏览器对象
  phantomjsdriver driver = new phantomjsdriver(dcaps);

  //设置隐性等待(作用于全局)
  driver.manage().timeouts().implicitlywait(1, timeunit.seconds);
  long start = system.currenttimemillis();
  //打开页面
  driver.get("https://juejin.im/post/5bb24bafe51d450e4437fd96");
  thread.sleep(30 * 1000);
  javascriptexecutor js = driver;
  for (int i = 0; i < 33; i++) {
   js.executescript("window.scrollby(0,1000)");
   //睡眠10s等js加载完成
   thread.sleep(5 * 1000);
  }
  //指定了outputtype.file做为参数传递给getscreenshotas()方法,其含义是将截取的屏幕以文件形式返回。
  file srcfile = ((takesscreenshot)driver).getscreenshotas(outputtype.file);
  thread.sleep(3000);
  //利用fileutils工具类的copyfile()方法保存getscreenshotas()返回的文件对象
  fileutils.copyfile(srcfile, new file("/users/hetiantian/desktop/juejin-01.png"));
  system.out.println("耗时:" + (system.currenttimemillis() - start) + " 毫秒");
 }
}

注释已经够详细了不多说了。唯一说一点:通过去执行js代码实现页面滑动,并且每次滑动都会通过睡眠保证有时间可以将 js加载进来。会调用33次滑动,因为phantomjs截取最大的高度为32767px(int  32位的最大整数),所以滑动33次可以保证能够截取到的最大页面部分其js已经是加载完成了的

附:window.scrollby(0,1000)、window.scrollto(0,1000)的区别

window.scrollby(0,1000)
window.scrollby(0,1000)
执行到这里页面滑动1000+1000px
window.scrollto(0,1000)
window.scrollto(0,1000)
执行到这里页面滑动到1000px处

window.scrollto(0, document.body.scrollheight可以滑动到页面底部,不选择有两个原因:

1)一下子滑动到底部js会来不及被加载

2)有些页面没有底部,可以一直滑动加载

注:这里所说的js来不及加载指的是:想要截取页面的js来不及加载

该方式的缺点:比较费时间。果然熊和鱼掌不可兼得也,统计了一下截取一张图片大概需要四分多钟

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。