java-selenium 實(shí)現(xiàn)網(wǎng)頁截圖

使用firefox瀏覽器無頭模式在內(nèi)存里渲染頁面,然后用selenium操作瀏覽器并解析截圖。需要安裝firefox(也支持chrome)颈畸,然后下載firefox 驅(qū)動(dòng) 詳見:https://github.com/mozilla/geckodriver/releases峻厚。下載完成后存放任意路徑,然后將代碼中的geckoDriver 改為驅(qū)動(dòng)的實(shí)際路徑即可焕毫。

import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 網(wǎng)頁截圖
 */
public class WebPageScreenShot {
    /**
     * fireFox驅(qū)動(dòng)路徑
     */
    String geckoDriver = "C:\\Program Files\\Python37\\geckodriver.exe";
    String type="png";

    public void loadPage(String logonUrl,String actionUrl,String resultPath) throws IOException, InterruptedException {
        System.setProperty("webdriver.gecko.driver", geckoDriver);//chromedriver服務(wù)地址
        FirefoxOptions firefoxOptions = new FirefoxOptions();
        firefoxOptions.addArguments("-headless");
        //firefoxOptions.addArguments("--start-maximized");
        //firefoxOptions.addArguments("--start-fullscreen");
        firefoxOptions.setHeadless(true);
        FirefoxDriver driver = new FirefoxDriver(firefoxOptions); //新建一個(gè)WebDriver 的對(duì)象,但是new 的是FirefoxDriver的驅(qū)動(dòng)
        driver.get(logonUrl);//打開指定的網(wǎng)站
        driver.findElement(By.id("J_username")).sendKeys(new String[]{"***"});
        driver.findElement(By.id("J_password")).sendKeys(new String[]{"***"});
        driver.findElement(By.id("loginBtn")).click();//登錄
        (new WebDriverWait(driver, 20)).until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".index-welcome-info")));//檢查到登錄成功
        driver.get(actionUrl);//打開指定的網(wǎng)站
        driver.manage().window().setSize(new Dimension(1900, 800));
        //driver.manage().window().maximize();
        String js1 = "return document.body.clientHeight.toString()";
        String js1_result = driver.executeScript(js1) + "";
        int height = Integer.parseInt(js1_result);
        List<String> files = new ArrayList<String>();
        int last_t = 0;
        for (int i = 0; i < 20; ) {
            int currentHeight = (i * height);
            String js = "window.scrollTo(0," + currentHeight + ");";
            driver.executeScript(js);
            js1 = "return document.body.scrollHeight.toString()+','+document.body.scrollTop.toString()";
            js1_result = driver.executeScript(js1) + "";
            /**
             *    real_scroll_h, real_top = js1_result.split(',')[0], js1_result.split(',')[1]
             *  22             #real_scroll_h, real_top 是當(dāng)前滾動(dòng)條長度和當(dāng)前滾動(dòng)條的top驶乾,作為是否繼續(xù)執(zhí)行的依據(jù)邑飒,由于存在滾動(dòng)條向下拉動(dòng)后會(huì)加載新內(nèi)容的情況,所以需要以下的判斷
             *  23             #如果這次設(shè)置的top成功级乐,則繼續(xù)滾屏
             */
            int real_scroll_h = Integer.parseInt(js1_result.split(",")[0]);
            int real_top = Integer.parseInt(js1_result.split(",")[1]);
            //#real_scroll_h, real_top 是當(dāng)前滾動(dòng)條長度和當(dāng)前滾動(dòng)條的top疙咸,作為是否繼續(xù)執(zhí)行的依據(jù),由于存在滾動(dòng)條向下拉動(dòng)后會(huì)加載新內(nèi)容的情況唇牧,所以需要以下的判斷
            if (real_top == currentHeight) {
                //  #如果這次設(shè)置的top成功罕扎,則繼續(xù)滾屏
                i++;
                files.add(screenshot(driver).getAbsolutePath());
                last_t = real_top;
            } else {
                // #如果本次設(shè)置失敗,看這次的top和上一次記錄的top值是否相等丐重,相等則說明沒有新加載內(nèi)容腔召,且已到頁面底,跳出循環(huán)
                if (real_top != last_t) {
                    last_t = real_top;
                } else {
                    files.add(screenshot(driver).getAbsolutePath());
                    break;
                }
            }
        }
        driver.quit();//退出瀏覽器
        merge(files.toArray(new String[]{}), type, resultPath);
    }


    private File screenshot(WebDriver driver) throws InterruptedException, IOException {
        try {
            /**
             * WebDriver自帶了一個(gè)智能等待的方法扮惦。
             dr.manage().timeouts().implicitlyWait(arg0, arg1)臀蛛;
             Arg0:等待的時(shí)間長度,int 類型 崖蜜;
             Arg1:等待時(shí)間的單位 TimeUnit.SECONDS 一般用秒作為單位浊仆。
             */
            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Thread.sleep(10000);//等等頁面加載完成
        /**
         * dr.quit()和dr.close()都可以退出瀏覽器,簡單的說一下兩者的區(qū)別:第一個(gè)close,
         * 如果打開了多個(gè)頁面是關(guān)不干凈的豫领,它只關(guān)閉當(dāng)前的一個(gè)頁面抡柿。第二個(gè)quit,
         * 是退出了所有Webdriver所有的窗口等恐,退的非常干凈洲劣,所以推薦使用quit最為一個(gè)case退出的方法。
         */
        byte[] imageBytes = (byte[]) ((FirefoxDriver) driver).getScreenshotAs(new OutputType<Object>() {
            public Object convertFromBase64Png(String s) {
                try {
                    return (new BASE64Decoder()).decodeBuffer(s);
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            public Object convertFromPngBytes(byte[] bytes) {
                return bytes;
            }
        });
        ByteArrayInputStream bytes = new ByteArrayInputStream(imageBytes);
        BufferedImage image = ImageIO.read(bytes);
        File file = File.createTempFile((new Random()).nextInt()+"",type);
        ImageIO.write(image, "png", file);
        return file;
    }

    /**
     * Java拼接多張圖片
     *
     * @param pics
     * @param type
     * @param dst_pic
     * @return
     */
    public static boolean merge(String[] pics, String type, String dst_pic) {

        int len = pics.length;
        if (len < 1) {
            System.out.println("pics len < 1");
            return false;
        }
        File[] src = new File[len];
        BufferedImage[] images = new BufferedImage[len];
        int[][] ImageArrays = new int[len][];
        for (int i = 0; i < len; i++) {
            try {
                src[i] = new File(pics[i]);
                images[i] = ImageIO.read(src[i]);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            int width = images[i].getWidth();
            int height = images[i].getHeight();
            ImageArrays[i] = new int[width * height];// 從圖片中讀取RGB
            ImageArrays[i] = images[i].getRGB(0, 0, width, height,
                    ImageArrays[i], 0, width);
        }

        int dst_height = 0;
        int dst_width = images[0].getWidth();
        for (int i = 0; i < images.length; i++) {
            dst_width = dst_width > images[i].getWidth() ? dst_width
                    : images[i].getWidth();

            dst_height += images[i].getHeight();
        }
        if (dst_height < 1) {
            System.out.println("dst_height < 1");
            return false;
        }

        // 生成新圖片
        try {
            // dst_width = images[0].getWidth();
            BufferedImage ImageNew = new BufferedImage(dst_width, dst_height,
                    BufferedImage.TYPE_INT_RGB);
            int height_i = 0;
            for (int i = 0; i < images.length; i++) {
                ImageNew.setRGB(0, height_i, dst_width, images[i].getHeight(),
                        ImageArrays[i], 0, dst_width);
                height_i += images[i].getHeight();
            }

            File outFile = new File(dst_pic);
            ImageIO.write(ImageNew, type, outFile);// 寫圖片

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }finally {
            /*
               刪除臨時(shí)文件
             */
            for(String tempFile:pics){
                File t=new File(tempFile);
                t.delete();
            }
        }

        return true;
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        WebPageScreenShot screenShot=new WebPageScreenShot();
        screenShot.loadPage("******","*******","D:\\TEST.png");
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xx.xx</groupId>
    <artifactId>java-selenium</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>
    </dependencies>


</project>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末课蔬,一起剝皮案震驚了整個(gè)濱河市囱稽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌二跋,老刑警劉巖战惊,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扎即,居然都是意外死亡吞获,警方通過查閱死者的電腦和手機(jī)况凉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衫哥,“玉大人茎刚,你說我怎么就攤上這事〕贩辏” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵粮坞,是天一觀的道長蚊荣。 經(jīng)常有香客問我,道長莫杈,這世上最難降的妖魔是什么互例? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮筝闹,結(jié)果婚禮上媳叨,老公的妹妹穿的比我還像新娘。我一直安慰自己关顷,他們只是感情好糊秆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著议双,像睡著了一般痘番。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上平痰,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天汞舱,我揣著相機(jī)與錄音,去河邊找鬼宗雇。 笑死昂芜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赔蒲。 我是一名探鬼主播泌神,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼嘹履!你這毒婦竟也來了腻扇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤砾嫉,失蹤者是張志新(化名)和其女友劉穎幼苛,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體焕刮,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舶沿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年墙杯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片括荡。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡高镐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出畸冲,到底是詐尸還是另有隱情嫉髓,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布邑闲,位于F島的核電站算行,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏苫耸。R本人自食惡果不足惜州邢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褪子。 院中可真熱鬧量淌,春花似錦、人聲如沸嫌褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渔扎。三九已至硫狞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晃痴,已是汗流浹背残吩。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倘核,地道東北人泣侮。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像紧唱,于是被迫代替她去往敵國和親活尊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容