How to get screenshot of full webpage using Selenium and Java?

Viewed 67389

How to take a screenshot of the entire web page (full-page screenshot), not only partial (top-to-bottom) using Selenium WebDriver?

My code: (Java bindings)

System.setProperty("webdriver.chrome.driver","/home/alex/Downloads/chromedriver_linux64/chromedriver");
WebDriver driver = new ChromeDriver();
driver.get("http://google.com");
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File(RESULT_FILENAME));

Any ideas on how to tackle this?

12 Answers

Now there's an easy way to do it with Selenium 4 and Firefox.

byte[] imageBytes = ((FirefoxDriver)driver).getFullPageScreenshotAs(OutputType.BYTES);
Files.write(Paths.get(RESULT_FILENAME), imageBytes);

Other browsers don't support getFullPageScreenshotAs() yet.

Looks like this article suggesting AShot works for me. Also, I successfully embeded the full page screenshot into Cucumber report with following code

    scenario.embed(takeScreenShotAsByte(getWebDriver()), "image/png");

    private static byte[] takeScreenShotAsByte(WebDriver webDriver) throws IOException {
        return takeFullPageScreenShotAsByte(webDriver);
    }

    private static byte[] takeFullPageScreenShotAsByte(WebDriver webDriver) throws IOException {
        Screenshot fpScreenshot = new AShot().shootingStrategy(ShootingStrategies.viewportPasting(1000))
                .takeScreenshot(webDriver);

        BufferedImage originalImage = fpScreenshot.getImage();

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            ImageIO.write(originalImage, "png", baos);
            baos.flush();
            return baos.toByteArray();
        }
    }

Here is my sample of get Full Screen ScreenShot using C#, but just change:

string _currentPath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(One of your objects)).Location) + @"\Attachs\";
var filePath = _currentPath + sSName;

if (!Directory.Exists(_currentPath))
    Directory.CreateDirectory(_currentPath);

Dictionary<string, Object> metrics = new Dictionary<string, Object>();
metrics["width"] = _driver.ExecuteScript("return Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)");
metrics["height"] = _driver.ExecuteScript("return Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)");
metrics["deviceScaleFactor"] = (double)_driver.ExecuteScript("return window.devicePixelRatio");
metrics["mobile"] = _driver.ExecuteScript("return typeof window.orientation !== 'undefined'");
_driver.ExecuteChromeCommand("Emulation.setDeviceMetricsOverride", metrics);

_driver.GetScreenshot().SaveAsFile(filePath, ScreenshotImageFormat.Png);

_driver.ExecuteChromeCommand("Emulation.clearDeviceMetricsOverride", new Dictionary<string, Object>());
_driver.Close();

It is possible to start Chrome in headless mode and then set the window size to the same height of the page body.

Since the height of your headless browser is not dependent on your monitor size you can use this headless mode to get full length screenshots as they are rendered in the Chrome browser.

The top answer for Headless Chrome run with selenium seems to show the right way to start Chrome in headless mode with java. I work with python bindings but the answer looks pretty similar to what I do.

This is the relevant part. This code should go before you start an instance of ChromeDriver.

ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--headless");

ChromeDriver driver = new ChromeDriver(chromeOptions);

If running chrome in a headless browser is not a viable option then you'll have to use Firefox or IE. Both of these browsers will give you a full length screenshot

Here is a way to use DevTools + Chromedriver to do it:

  private String takeScreenshot(ChromeDriver driver, boolean fullscreen) {
    if (fullscreen) {
      Map<String, Object> layoutMetrics = driver.executeCdpCommand("Page.getLayoutMetrics", Collections.emptyMap());
      Map<String, Object> screenshotConfig = Maps.newHashMap();
      screenshotConfig.put("captureBeyondViewport", true);
      screenshotConfig.put("fromSurface", true);
      Map contentSize = (Map)layoutMetrics.get("contentSize");
      screenshotConfig.put("clip", ImmutableMap.of(
          "width", contentSize.get("width"),
          "height", contentSize.get("height"),
          "x", 0,
          "y", 0,
          "scale", 1
      ));
      Map<String, Object> base64PngResult = driver.executeCdpCommand("Page.captureScreenshot", screenshotConfig);
      return (String)base64PngResult.get("data");
    }
    return driver.getScreenshotAs(OutputType.BASE64);
  }

For some pages I neeed to take screenshot of begin and end of page. So I use to take 2 screenshots:

public static String javaIoTmpDir = System.getProperty("java.io.tmpdir"); //tmp dir
//create screenshot
    driver.manage().window().fullscreen();
    //For large pages - body over 850 px highh - take addition screenshot of the end of page
    if (driver.findElements(By.id("panel_body")).size()>0) {
        WebElement body = driver.findElement(By.id("panel_body"));
        int bodyHight = body.getSize().getHeight();
        if (bodyHight > 850) {
            Robot robot = new Robot();
            robot.keyPress(KeyEvent.VK_END);
            robot.keyRelease(KeyEvent.VK_END);
            Thread.sleep(1000);
            File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            String timePictureEnd = javaIoTmpDir+"\\scr_"+String.valueOf(System.currentTimeMillis())+getClass().toString().substring(getClass().toString().lastIndexOf(".qa.")+3)+".png";
            FileUtils.copyFile(scrFile, new File(timePictureEnd));
            robot.keyPress(KeyEvent.VK_HOME); //back to top page for next screen
            robot.keyRelease(KeyEvent.VK_HOME);
            Thread.sleep(1000);
        }
    }
    String timePicture = javaIoTmpDir+"\\scr_"+String.valueOf(System.currentTimeMillis())+getClass().toString().substring(getClass().toString().lastIndexOf(".qa.")+3)+".png";
    File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(scrFile, new File(timePicture));

You can use Phantomjs to achieve it.

Here is my java code:

public class PhantomjsTest {
    public static void main(String[] args) {
        try {

            long start=System.currentTimeMillis();
            //The page you want to screenshot
            String targetUrl="https://www.iqiyi.com/";
            //File path
            String targetImg="iqiyi.png";
            String command = "/Users/hetiantian/SoftWares/phantomjs/bin/phantomjs /Users/hetiantian/SoftWares/phantomjs/examples/rasterize.js "+targetUrl + " " +targetImg;
            Process p = Runtime.getRuntime().exec(command);
            p.waitFor();
            System.out.println((System.currentTimeMillis()-start));
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

So you can get a screenshot of full webpage by Phantomjs. When you use Phantomjs to get a full screenshot, you need to download Phantomjs first. Then run Phantomjs script to screenshot. More about it you can reference phantomjs.org.

Java code without using third party library:

int bodyHeight = webDriver.findElement(By.tagName("body")).getSize().getHeight();
int windowChromeHeight = (int) (long) webDriver.executeScript("return window.outerHeight - window.innerHeight");
Dimension size = new Dimension(webDriver.manage().window().getSize().getWidth(), bodyHeight + windowChromeHeight);
webDriver.executeScript("window.scrollTo(0, 0);");
webDriver.manage().window().setSize(size);
            
File screenshotFile = new File("screenshot.png");
Files.write(screenshotFile.toPath(), webDriver.getScreenshotAs(OutputType.BYTES));

None of the options described here worked for me in my environment (go lang, chromedriver, fedesog implementation of web driver) What came to me eventually is zoom out! This approach can work for pages which are not too long, in which zooming out makes sense.

I think this may be relevant for java or any other language using selenium, so posting it here for anyone who comes across this issue in any programming language :) The following javascript code snippet allows to set zoom level:

document.body.style.zoom = '0.5'

Where 0.5 is the zoom level you want. It can be calculated dynamically based on actual page size, which can be retrieved using:

document.body.scrollHeight

and

document.body.scrollWidth

like mentioned above, and executed like:

webDriver.executeScript(...)

in java or

session.ExecuteScript(...)

in golang using fedesog or similar webdriver framework

Related