使用PhantomJS實現網頁截圖服務


    這是上半年遇到的一個小需求,想實現網頁的抓取,並保存為圖片。研究了不少工具,效果都不理想,不是顯示太差了(Canvas、Html2Image、Cobra),就是性能不怎么樣(如SWT的Brower)。后發現無界面瀏覽器可以滿足這個條件,大致研究了一下PhantomJS與CutyCapt,兩者都是Webkit內核,其中PhantomJS使用上更方便一些,尤其在Windows平台上,如果在Linux下,從2.0版本后需要自己去機器上編譯了(大概要編譯3個小時,不得不說,g++就是個渣渣,同樣的項目,在vc下編譯快得,不談了,畢竟是免費開源的編譯器)。下面介紹PhantomJS結合Java代碼實現的網頁截圖技術:

   

 一、環境准備

    1、PhantomJS腳本的目錄:D:/xxx/phantomjs-2.0.0-windows/bin/phantomjs

    2、截圖腳本:D:/xxx/phantomjs-2.0.0-windows/bin/rasterize.js

    截圖的腳本在官網上有提供,但是我這里需要說明一下它的高寬度設計原理:

page.viewportSize = { width: 600, height: 600 };

   這個是默認的高度,也就是600X600,我建議大家把height設置小一點,我這邊設置的是width:800,height:200。因為實際上,在不同時設置高度與亮度的情況下,如果真實的網頁的高度大於設置值時,圖片會自動擴充高寬度的,直到整個頁面顯示完(當你想截取小的圖片時,可能由於默認設置的太大,會使圖片有很大一塊空的)。如果同時設置了高寬度,下面的代碼會被執行,就會對網頁的部分進行截取了:

page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };

    3、先用命令行測試一下:    

D:/xxx/phantomjs-2.0.0-windows/bin/phantomjs D:/xxx/phantomjs-2.0.0-windows/bin/rasterize.js http://www.qq.com D:/test.png

    如果配置好了,應該可以看到生成的圖片了。當然還可以配置高寬度的參數,在上面的命令后加上:" 1000px"或" 1000px*400px",都是可以的。

 

二、服務器代碼

    作為一個網頁截圖服務,這部分代碼片段應當被布署在服務器上,當然不必全照搬啦,根據自己的需求來用就好了:

  1 package lekkoli.test;
  2 
  3 import java.io.BufferedInputStream;
  4 import java.io.BufferedReader;
  5 import java.io.ByteArrayOutputStream;
  6 import java.io.File;
  7 import java.io.FileInputStream;
  8 import java.io.IOException;
  9 import org.apache.log4j.Logger; 
 10 
 11 /**
 12  * 網頁轉圖片處理類,使用外部CMD
 13  * @author lekkoli
 14  */
 15 public class PhantomTools {
 16 
 17     private static final Logger _logger = Logger.getLogger(PhantomTools.class);
 18 
 19     // private static final String _tempPath = "/data/temp/phantom_";
 20     // private static final String _shellCommand = "/usr/local/xxx/phantomjs /usr/local/xxx/rasterize.js ";  Linux下的命令
 21     private static final String _tempPath = "D:/data/temp/phantom_";
 22     private static final String _shellCommand = "D:/xxx/phantomjs-2.0.0-windows/bin/phantomjs D:/xxx/phantomjs-2.0.0-windows/bin/rasterize.js ";    
 23 
 24     private String _file;
 25     private String _size;
 26 
 27     /**
 28      * 構造截圖類
 29      * @parm hash 用於臨時文件的目錄唯一化
 30      */
 31     public PhantomTools(int hash) {
 32         _file = _tempPath + hash + ".png";
 33     }
 34 
 35     /**
 36      * 構造截圖類
 37      * @parm hash 用於臨時文件的目錄唯一化
 38      * @param size 圖片的大小,如800px*600px(此時高度會裁切),或800px(此時 高度最少=寬度*9/16,高度不裁切)
 39      */
 40     public PhantomTools(int hash, String size) {
 41         this(hash);
 42         if (size != null)
 43             _size = " " + size;
 44     }
 45 
 46     /**
 47      * 將目標網頁轉為圖片字節流
 48      * @param url 目標網頁地址
 49      * @return 字節流
 50      */
 51     public byte[] getByteImg(String url) throws IOException {
 52         BufferedInputStream in = null;
 53         ByteArrayOutputStream out = null;
 54         File file = null;
 55         byte[] ret = null;
 56         try {
 57             if (exeCmd(_shellCommand + url + " " + _file + (_size != null ? _size : ""))) {
 58                 file = new File(_file);
 59                 if (file.exists()) {
 60                     out = new ByteArrayOutputStream();
 61                     byte[] b = new byte[5120];
 62                     in = new BufferedInputStream(new FileInputStream(file));
 63                     int n;
 64                     while ((n = in.read(b, 0, 5120)) != -1) {
 65                         out.write(b, 0, n);
 66                     }
 67                     file.delete();
 68                     ret = out.toByteArray();
 69                 }
 70             } else {
 71                 ret = new byte[] {};
 72             }
 73         } finally {
 74             try {
 75                 if (out != null) {
 76                     out.close();
 77                 }
 78             } catch (IOException e) {
 79                 _logger.error(e);
 80             }
 81             try {
 82                 if (in != null) {
 83                     in.close();
 84                 }
 85             } catch (IOException e) {
 86                 _logger.error(e);
 87             }
 88             if (file != null && file.exists()) {
 89                 file.delete();
 90             }
 91         }
 92         return ret;
 93     }
 94 
 95     /**
 96      * 執行CMD命令
 97      */
 98     private static boolean exeCmd(String commandStr) {
 99         BufferedReader br = null;
100         try {
101             Process p = Runtime.getRuntime().exec(commandStr);
102             if (p.waitFor() != 0 && p.exitValue() == 1) {
103                 return false;
104             }
105         } catch (Exception e) {
106             _logger.error(e);
107         } finally {
108             if (br != null) {
109                 try {
110                     br.close();
111                 } catch (Exception e) {
112                     _logger.error(e);
113                 }
114             }
115         }
116         return true;
117     }
118 }

    使用上面的PhantomTools類,可以很方便地調用getByteImg方法來生成並獲取圖片內容。  

     

    附上我的截圖配置腳本:rasterize.js,至於PhantomJS,大家就自行去官網下載吧。

    轉載請注明原址:http://www.cnblogs.com/lekko/p/4796062.html  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM