在爬蟲開發過程中,或者其他方面有時候會有這種需求,截取網頁圖檔,作為一種快照資訊進行存儲,在最近開發過程中也剛好碰到了這種需求,需要将爬蟲過程中的網頁進行快照資訊儲存,是以檢視了一部分文檔,現提供以下兩種方式進行快照截圖。
Python版本
python需要安裝selenium,通過pip方式便可安裝,期中下面有三種方式:
1. 調用Chrome或者FireFox浏覽器方式,這種都需要打開本地一個無頭浏覽器,而這個浏覽器需要自己單獨下載下傳,否則會報異常,網上例子很多,不再描述,下載下傳後放置與python.exe同級目錄便可運作,這兩種方式都隻能截取浏覽器部分截圖,如果該頁面有滾動條,那麼下面頁面是無法截取到的。
2. 調用PhantomJS方式,這種就是解決滾動截屏問題,可以自動将目前浏覽器頁面全部内容截取,并且不打開浏覽器,不用額外安裝其他東西,至于其他帶cookie,post,get不同請求請查閱其他資料。
from selenium import webdriver
# 使用PhantomJS擷取浏覽器截圖,會截取整個網頁資訊,包含滾動條以下部分
br = webdriver.PhantomJS()
br.maximize_window()
br.get("http://www.baidu.com")
br.save_screenshot("./baidu01.png")
# 使用chrome浏覽器擷取浏覽器截圖,隻會截取展現部分
br = webdriver.Chrome()
br.maximize_window()
br.get("http://www.baidu.com")
br.save_screenshot("./baidu02.png")
# 使用Firefox浏覽器擷取浏覽器截圖,隻會截取展現部分
br = webdriver.Firefox()
br.maximize_window()
br.get("http://www.baidu.com")
br.save_screenshot("./baidu03.png")
JAVA版本
Java主要兩種方式:
一種是Robot方式,這種截圖不但可以截圖,還可以實作一起操控類,截圖隻是它一個小功能,例子中也隻是簡單打開浏覽器,截取目前顯示部分,然後儲存成圖檔,關閉浏覽器,是以對于存在滾動條的,無法全部截取,因為要模拟操控滾動條,形成一個輸入流,循環讀取,顯得太過于麻煩,不太通用。不過Robot最主要的并不是截圖,而是操控,沒準需要固定點選的可以用該方式模拟操作呢。
public class CutPicture {
/**
* 圖像截取并儲存
* @param url: 請求連結
* @throws MalformedURLException
* @throws IOException
* @throws URISyntaxException
* @throws AWTException
*/
public static void saveHtmlImg(String url) throws IOException, URISyntaxException, AWTException {
Desktop.getDesktop().browse(new URL(url).toURI());
Robot robot = new Robot();
robot.delay(2000);
Dimension d = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());
int width = (int) d.getWidth();
int height = (int) d.getHeight();
// 最大化浏覽器
robot.keyRelease(KeyEvent.VK_F11);
robot.delay(2000);
/**
* 所有操作浏覽器方法都在此設定
* 如設定滑鼠滾軸向下:robot.mouseWheel(KeyEvent.VK_DOWN);
* 每項設定後都需增加延遲robot.delay()
* Robot 對螢幕截取隻是一點小小的功能,而實際它可以自定義很多方法去實際操控電腦,是以慎用
*/
Image image = robot.createScreenCapture(new Rectangle(0, 0, width, height));
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
/**
* x:截圖x軸起點
* y: 截圖y軸起點,防止截取浏覽器搜尋框,是以設定為-100,相應height+100
*/
g.drawImage(image, 0, -100, width, height+100, null);
// 儲存圖檔
File fileOut = new File("./imgHtml");
fileOut.mkdirs();
ImageIO.write(bi, "jpg", new File("./imgHtml/001.jpg"));
//關閉浏覽器
closeBrowse();
}
/**
* 關閉浏覽器
*/
public static void closeBrowse(){
try {
Runtime.getRuntime().exec("taskkill /F /IM chrome.exe");
Runtime.getRuntime().exec("taskkill /F /IM iexplorer.exe");
Runtime.getRuntime().exec("taskkill /F /IM 360se.exe");
Runtime.getRuntime().exec("taskkill /F /IM firefox.exe");
Runtime.getRuntime().exec("taskkill /F /IM iexplorer.exe");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws AWTException, IOException, URISyntaxException {
String url = "http:www.baidu.com";
String url2 = "http://top.baidu.com/?fr=mhd_card";
saveHtmlImg("http:www.baidu.com");
}
}
另一種則是PhantomJs方式,其實就是python版本的Java對應,但是需要提前下載下傳phantomjs,網上連結很多,通過這種方式的截屏,則可以實作滾動截屏,但是截屏,截取多少,怎麼截取,其實靠它的配置檔案一個js檔案控制,phantomjs官方js檔案怎麼寫,網上demo很多,其實java隻是調用,至于怎麼截取,怎麼用,完全靠js檔案編寫。
public class PhantomTools {
/**
* 本地連結中文轉Unicode碼
* @param url
* @return
*/
public static String chineseToUnicode(String url){
StringBuffer sb = new StringBuffer();
for (int i = 0; i < url.length(); i++) {
char c = url.charAt(i);
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
byte[] b;
try {
b = String.valueOf(c).getBytes("utf-8");
} catch (Exception ex) {
System.out.println(ex);
b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0)
k += 256;
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
/**
* 圖檔截取,以下兩個路徑根據自己工程目錄更改
* phantomjsPath:phantomjs.exe路徑
* cutPictureJsPath:截圖javascript腳本的路徑
* @param url
* @throws IOException
*/
public static void cutPicturl(String url) throws IOException {
String basePath = System.getProperty("user.dir")+"\\";
String BLANK = " ";
//phantomjs.exe路徑
String phantomjsPath = basePath+"pictureHtmlSpider\\src\\PhantomCutPicture\\staticPhantomJs\\phantomjs.exe" + BLANK;
//截圖javascript腳本的路徑 E:\JAVA_PROJECT\imgHtmlSpider\pictureHtmlSpider\src\PhantomCutPicture\staticPhantomJs\rasterize.js
String cutPictureJsPath = basePath+"pictureHtmlSpider\\src\\PhantomCutPicture\\staticPhantomJs\\rasterize.js" + BLANK;
//url位址
String urlPath = chineseToUnicode(url)+BLANK;
// 儲存圖檔
String filePath = "./imgHtml";
/**這裡如果要改變檔案夾名字imgHTML,需要同時更改cutPictureMain()方法中的if判斷*/
File fileOut = new File(filePath);
fileOut.mkdirs();
//輸出目錄
Random random = new Random();
String savePath = filePath+"/"+(random.nextInt(10)+1000)+".png";
System.out.println(savePath);
/**
* 調用phantomjs
* phantomjsPath:phantomjs路徑
* cutPictureJsPath:rasterize.js路徑,全屏截圖配置就在此編寫,定制化截屏也需更改此檔案
* 網頁帶cookie請求也需要編寫此js檔案,便可帶cookie通路,适用于爬蟲開發
* urlPath:網頁請求
* savePath:圖檔儲存路徑
*/
Process process = Runtime.getRuntime().exec(phantomjsPath
+ cutPictureJsPath
+ urlPath
+ savePath);
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
int tmp=0;
while (br.readLine() != null)
{
tmp+=1;
System.out.println("==> Start cutPicture :"+tmp+" page");
}
}
public static void main(String[] args) throws IOException {
String url = "http:www.baidu.com";
String url2 = "http://top.baidu.com/?fr=mhd_card";
cutPicturl(chineseToUnicode(url2));
}
}
它的配置rasterize.js檔案:
"use strict";
var page = require('webpage').create(),
system = require('system'),
address, output, size;
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36';
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: 800, height: 900 };
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);
}
});
}
以上例子都經過測試,可以對浏覽器中包含滾動條的全部截屏。