java使用phantomjs進行截圖

斷斷續(xù)續(xù)查找資料躬存、驗證不同的實現(xiàn)方法終于算基本搞定了頁面截圖端壳,因為中間過程曲折花費較多時間,分享出來幫助大家快速實現(xiàn)截圖

為什么選用phantomjs進行截圖

截圖可以實現(xiàn)的方式有很多,比如:

  • selenium
  • HtmlUnit
  • Html2Image
    稠曼、碱屁、磷脯、and so on
    但是這些實現(xiàn)的截圖效果都不好。selenium只能實現(xiàn)截屏娩脾,不能截取整個頁面赵誓,而HtmlUnit、Html2Image對js的支持效果并不好,截下來的圖會有很多空白俩功。phantomjs就是萬精油了幻枉,既能截取整個頁面,對js支持的效果又好

前期準備

安裝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
  • 查看效果


    juejin-command.png

    發(fā)現(xiàn)圖片沒有加載好


    難受

來看以下剛剛的命令行:
/Users/hetiantian/SoftWares/phantomjs/bin/phantomjs:phantomjs可執(zhí)行文件保存地址
/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調大十倍椿肩,發(fā)現(xiàn)基本是完美截圖了,但是如果頁面的篇幅特別短豺谈,會發(fā)現(xiàn)有瑕疵郑象,下面留有一大片空白。原因:page.viewportSize = { width: 600, height: 600 };設置的是初始打開瀏覽器的大小茬末,通過增大這個值可以加載js厂榛。如果我們能拿到實際頁面的大小在設置height大小,但是不丽惭,我不能击奶。

難受.jpeg

并且不能接受預先設定一個很大的height值,比如30000吐根,因為不能接受底下留白的效果
嘗試二:
在window.setTimeout方法之前加入以下代碼

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

無奈evaluate里不能在用for循環(huán)了正歼,前端渣渣真的不知道如何改,遂放棄

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>

  • 代碼實現(xiàn)
public class PhantomjsTest2 {
    public static void main(String[] args) throws InterruptedException, IOException {
        //設置必要參數(shù)
        DesiredCapabilities dcaps = new DesiredCapabilities();
        //ssl證書支持
        dcaps.setCapability("acceptSslCerts", true);
        //截屏支持
        dcaps.setCapability("takesScreenshot", true);
        //css搜索支持
        dcaps.setCapability("cssSelectorsEnabled", true);
        //js支持
        dcaps.setJavascriptEnabled(true);
        //驅動支持(第二參數(shù)表明的是你的phantomjs引擎所在的路徑)
        dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
                "/Users/hetiantian/SoftWares/phantomjs/bin/phantomjs");
        //創(chuàng)建無界面瀏覽器對象
        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做為參數(shù)傳遞給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) + " 毫秒");
    }
}

注釋已經夠詳細了不多說了。唯一說一點:通過去執(zhí)行js代碼實現(xiàn)頁面滑動冗疮,并且每次滑動都會通過睡眠保證有時間可以將 js加載進來萄唇。會調用33次滑動,因為phantomjs截取最大的高度為32767px(int 32位的最大整數(shù))术幔,所以滑動33次可以保證能夠截取到的最大頁面部分其js已經是加載完成了的
附:window.scrollBy(0,1000)另萤、window.scrollTo(0,1000)的區(qū)別

window.scrollBy(0,1000)
window.scrollBy(0,1000)
執(zhí)行到這里頁面滑動1000+1000px
window.scrollTo(0,1000)
window.scrollTo(0,1000)
執(zhí)行到這里頁面滑動到1000px處

window.scrollTo(0, document.body.scrollHeight可以滑動到頁面底部,不選擇有兩個原因:
1)一下子滑動到底部js會來不及被加載
2)有些頁面沒有底部诅挑,可以一直滑動加載
注:這里所說的js來不及加載指的是:想要截取頁面的js來不及加載
該方式的缺點:比較費時間四敞。果然熊和魚掌不可兼得也,統(tǒng)計了一下截取一張圖片大概需要四分多鐘
===================更新于2018.10.15====================

phantomjs的缺點

  • 有最大截圖長度32767px
  • 可能會出現(xiàn)跨越的問題
  • 需要裝瀏覽器驅動

可以使用google的puppeteer完成截圖功能:
附簡單demo:

const puppeteer = require('/usr/local/lib/node_modules/puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false
    });
    const page = await browser.newPage();
    // await page.goto('https://www.zhihu.com/question/22263777');
    await page.goto('http://www.iqiyi.com');
    await page.setViewport({
        width: 1200,
        height: 800
    });

    await autoScroll(page);

    await page.screenshot({
        path: 'jd.png',
        fullPage: true
    });

    await browser.close();
})();


function autoScroll(page) {
    return page.evaluate(() => {
        return new Promise((resolve, reject) => {
            var totalHeight = 0;
            var distance = 100;
            var timer = setInterval(() => {
                var scrollHeight = document.body.scrollHeight;
                window.scrollBy(0, distance);
                totalHeight += distance;

                if (totalHeight >= scrollHeight) {
                    clearInterval(timer);
                    resolve();
                }
            }, 100);
        })
    });
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末拔妥,一起剝皮案震驚了整個濱河市忿危,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌没龙,老刑警劉巖铺厨,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缎玫,死亡現(xiàn)場離奇詭異,居然都是意外死亡解滓,警方通過查閱死者的電腦和手機赃磨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洼裤,“玉大人邻辉,你說我怎么就攤上這事∫莅睿” “怎么了恩沛?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缕减。 經常有香客問我雷客,道長,這世上最難降的妖魔是什么桥狡? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任搅裙,我火速辦了婚禮,結果婚禮上裹芝,老公的妹妹穿的比我還像新娘部逮。我一直安慰自己,他們只是感情好嫂易,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布兄朋。 她就那樣靜靜地躺著,像睡著了一般怜械。 火紅的嫁衣襯著肌膚如雪颅和。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天缕允,我揣著相機與錄音峡扩,去河邊找鬼。 笑死障本,一個胖子當著我的面吹牛教届,可吹牛的內容都是我干的。 我是一名探鬼主播驾霜,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼案训,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了粪糙?” 一聲冷哼從身側響起萤衰,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猜旬,沒想到半個月后脆栋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡洒擦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年椿争,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熟嫩。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡秦踪,死狀恐怖,靈堂內的尸體忽然破棺而出掸茅,到底是詐尸還是另有隱情椅邓,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布昧狮,位于F島的核電站景馁,受9級特大地震影響,放射性物質發(fā)生泄漏逗鸣。R本人自食惡果不足惜合住,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撒璧。 院中可真熱鬧透葛,春花似錦、人聲如沸卿樱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽繁调。三九已至萨蚕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涉馁,已是汗流浹背门岔。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留烤送,地道東北人寒随。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像帮坚,于是被迫代替她去往敵國和親妻往。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,152評論 25 707
  • 用兩張圖告訴你试和,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料讯泣? 從這篇文章中你...
    hw1212閱讀 12,727評論 2 59
  • 從出生相伴的你 不知何時離開了 不帶一點猶豫和傷感 和傷心為伍的你枯萎在土地里 是悲痛太炙熱 抑或你已經習慣這塵世...
    傷陽閱讀 350評論 0 1
  • 感賞自己一大早起床學習,大聲讀書阅悍,也帶動了同事學習的積極性『们現(xiàn)在感覺到自己是一個一直在學習中的人昨稼,從來沒有止步不前...
    阿梨梨梨閱讀 165評論 0 3
  • 今天上午給兒子做好早飯,哄他起床吃飯拳锚,習慣性跟我撒嬌的他依舊磨蹭了會才起床假栓,我等著他洗漱完過來吃飯,早飯后霍掺,...
    鍇博麻麻閱讀 131評論 0 1