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

前言

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

为什么选用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

查看效果

发现图片没有加载好

来看以下刚刚的命令行:

/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来不及加载

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

总结

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

(0)

相关推荐

  • JS打开摄像头并截图上传示例

    直入正题,JS打开摄像头并截图上传至后端的一个完整步骤 1. 打开摄像头主要用到getUserMedia方法,然后将获取到的媒体流置入video标签 2. 截取图片主要用到canvas绘图,使用drawImage方法将video的内容绘至canvas中 3. 将截取的内容上传至服务器,将canvas中的内容转为base64格式上传,后端(PHP)通过file_put_contents将其转为图片 要注意的是,在chrome以外的浏览器中,使用摄像头或多或少会出现一些问题,可能也是老问题了,所以以

  • JavaScript实现网页截图功能

    使用JavaScript截图,这里我要推荐两款开源组件:一个是Canvas2Image,它可以将Canvas绘图编程PNG/JPEG/BMP的图像:但是光有它还不够,我们需要给任意DOM(至少是绝大部分)截图,这就需要html2canvas,它可以将DOM对象转换成一个canvas对象.两者的功能结合起来,就可以把页面上的DOM截图成PNG或者JPEG图像了,很酷. Canvas2Image 它的原理是利用了HTML5的canvas对象提供了toDataURL()的API: 复制代码 代码如下:

  • JS中使用cavas截图网页并解决跨域及模糊问题

    前几天给了个需求对浏览器网页进行截图,把网页统计数据图形表等截图保存至用户本地. 首先对于网页截图,我用的是canvas实现,获取你需要截图的模块的div,从而使用canvas对你需要的模块进行截图. 我们先来引入canvas的js文件,js文件获取地址官网主页:http://html2canvas.hertzen.com/ <script type="text/javascript" src="js/html2canvas.js"></scrip

  • JavaScript+html5 canvas实现本地截图教程

    最近有时间了解了下html5的各API,发现新浪微博的头像设置是使用canvas实现截图的,加之前段时间了解了下html5的File API使用File API 之FileReader实现文件上传<JavaScript File API文件上传预览>,更加觉得html5好玩了,想着也试试写写这功能权当学习canvas吧. 下面奉上我自己写的一个demo,代码写得比较少,很多细节不会处理.如果有不得当的地方恳请指教,谢谢啦 ^_^ ^_^ 功能实现步奏: 一.获取文件,读取文件并生成url 二.

  • JS实现div模块的截图并下载功能

    当需要实现html页面部分模块截图并具有保存图片功能时,前台直接生成截图并下载会方便的多.多的不说,直接看代码 首先我们需要引入2个js文件: <script type="text/javascript" src="js/html2canvas.js"></script> <script type="text/javascript" src="js/jquery-1.12.3.min.js">

  • js实现截图保存图片功能的代码示例

    前几天公司项目里有这样一个需求,把网页的某一部分能够一键截图.这个功能其实就是对人力的一个优化,如果是人为做的话,相信大家都知道怎么做(用截图工具在指定区域截图,然后保存到本地,再上传的服务器上去).我这个主要就解决这个批量的人力的优化.好,废话不多说了.直接上逻辑和代码.' 这个问题的解决方案:html to canvas to png. 目前有一个这样的插件: html2canvas, html2canvas($targetElem, { useCORS: true, onrendered:

  • 原生js基于canvas实现一个简单的前端截图工具代码实例

    这篇文章主要介绍了原生js基于canvas实现一个简单的前端截图工具代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 先看效果 代码如下 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> *{

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

    前言 最近工作中遇到一个需求,需要实现截图功能,断断续续查找资料.验证不同的实现方法终于算基本搞定了页面截图,因为中间过程曲折花费较多时间,分享出来帮助大家快速实现截图 为什么选用phantomjs进行截图 截图可以实现的方式有很多,比如: selenium HtmlUnit Html2Image...and so on但是这些实现的截图效果都不好.selenium只能实现截屏,不能截取整个页面,而HtmlUnit.Html2Image对js的支持效果并不好,截下来的图会有很多空白.phanto

  • Java后端Tomcat实现WebSocket实例教程

    一.WebSocket简单介绍 WebSocket protocol 是HTML5一种新的协议.它实现了浏览器与服务器全双工通信(full-duplex).一开始的握手需要借助HTTP请求完成握手. 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据. WebSocket背景 在浏览器中通过http仅能实现单向的

  • Java利用Phantomjs实现生成图片的功能

    今天,给大家分享一个Java后端利用Phantomjs实现生成图片的功能,同学们使用的时候,可以参考下! PhantomJS简介 首先,什么是PhantomJS? 根据官网介绍: PhantomJS is a command-line tool. -- 其实就是一个命令行工具. PhantomJS的下载地址: Windows:phantomjs-2.1.1-windows.zip Linux:phantomjs-2.1.1-linux-x86_64.tar.bz2;phantomjs-2.1.1

  • Java中利用gson解析Json实例教程

    前言 本文主要跟大家介绍了关于Java用gson解析Json的相关内容,分享出来供大家参考学习,需要的朋友们下面来一起看看吧. json数据 { "resultcode": "200", "reason": "successed!", "result": { "sk": { "temp": "24", "wind_direction&qu

  • Java利用for循环打印菱形的实例教程

    Java for循环打印菱形 Java代码输出菱形的方法和思路有很多,在此分享一个稍带模块化拆分思想的解决方案,将需要输出的菱形拆分成8个模块(如下图),每个模块独立实现输出. 优点:8个模块之间耦合性降低,灵活性增强.也就是说我们可以独立的控制这8个模块中任意一个模块的输出内容来灵活应对业务逻辑的变更. 按照上图标好的顺序依次实现这8个模块的代码,当1458模块输出为空格时,其中2367模块的组合,就是一个菱形. 思路分析: 1      ######*######  第一排 模块1[6个"#

  • Java利用Zxing生成二维码的简单实例

    Zxing是Google提供的关于条码(一维码.二维码)的解析工具,提供了二维码的生成与解析的方法,现在我简单介绍一下使用Java利用Zxing生成与解析二维码 1.二维码的生成 1.1 将Zxing-core.jar 包加入到classpath下. 1.2 二维码的生成需要借助MatrixToImageWriter类,该类是由Google提供的,可以将该类拷贝到源码中,这里我将该类的源码贴上,可以直接使用. import com.google.zxing.common.BitMatrix; i

  • JAVA利用HttpClient进行POST请求(HTTPS)实例

    最近,需要对客户的接口做一个包装,然后供自己公司别的系统调用,客户接口是用HTTP URL实现的,我想用HttpClient包进行请求,同时由于请求的URL是HTTPS的,为了避免需要证书,所以用一个类继承DefaultHttpClient类,忽略校验过程. 1.写一个SSLClient类,继承至HttpClient package com.pcmall.service.sale.miaomore.impl; import java.security.cert.CertificateExcept

  • Java利用自定义注解、反射实现简单BaseDao实例

    在常见的ORM框架中,大都提供了使用注解方式来实现entity与数据库的映射,这里简单地使用自定义注解与反射来生成可执行的sql语句. 这是整体的目录结构,本来是为复习注解建立的项目^.^ 好的,首先我们来确定思路. 1. 自定义@Table @Column注解, 我们稍微模仿hibernate,让@Table作用于类上,来表明实体类与数据表的映射关系,且让@Table中的属性value映射为数据表的名称tableName:让@Column作用于属性上(这里没实现作用于set方法上),表明属性与

  • 利用Java理解sql的语法(实例讲解)

    select 相当于 for 循环 select id from IDArray LinkedList a = new LinkedList(); for ( int i=0 ; i<tableA.length ; i++){ a.add(IDArray.get("id" ) ); } return a; 当执行子查询时,可以理解为 select id, ( select name from nameArray) as names ,from Idarray LinkedList

  • Java利用openoffice将doc、docx转为pdf实例代码

    本文研究的主要是Java编程利用openoffice将doc.docx转为pdf的实现代码,具体如下. 1. 需要用的软件 OpenOffice , JodConverter 2.启动OpenOffice的服务 我到网上查如何利用OpenOffice进行转码的时候,都是需要先用cmd启动一个soffice服务,启动的命令是:soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;". 但是实际上,对于我的项目,进行转

随机推荐