1
votes

Objective: Scroll in equivalent intervals to take screenshot of an entire page using Java and JSExecutor for Selenium WebDriver.

Issue: The approach I've implemented below works, however, I end up having 2-3 extra screenshots at the end of the web page - I want to avoid these redundant screenshots.

Scrolling method is below:

public static void pageScrollable() throws InterruptedException, IOException {

    JavascriptExecutor jse = (JavascriptExecutor) driver;

    //Find page height
    pageHeight = ((Number) jse.executeScript("return document.body.scrollHeight")).intValue();
    //Find current browser dimensions and isolate its height
    Dimension d = driver.manage().window().getSize();
    int browserSize = d.getHeight();

    int currentHeight = 0;      
    System.out.println("Current scroll at: " + currentHeight);
    System.out.println("Page height is: " + pageHeight + "\n");

    //Scrolling logic
    while(pageHeight>=currentHeight) {  
        jse.executeScript("window.scrollBy(0,"+currentHeight+")", "");
        screenShot();
        currentHeight+=browserSize;
        System.out.println("Current scroll now at: " + currentHeight);
    }   
}

Screenshot method is below:

public static void screenShot() throws IOException, InterruptedException {
    File screenShot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(screenShot, new File("C:\\FilePath\\Screen " + count + ".png"));
    count++;
    System.out.println("Current screenshot count: " + count);
}

Following variables are defined as static:

static int pageHeight = 0;
static int count = 0;
static WebDriver driver;

I understand there's no implementation currently to capture screen of an entire web page using Selenium. Any help to resolve my logic above would be greatly appreciated.

1

1 Answers

1
votes

Your scrolling logic is the reason for the additional image. The Window.scrollBy method scrolls by a number of pixel and not to an absolute position. You need to scroll by browserSize.

And perhaps you should identify the viewport size instead of the browser window size with

int browserSize = ((Number) jse.executeScript("return window.innerHeight")).intValue();

I added a complete example how to get single page screenshots with Chrome:

package demo;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import javax.imageio.ImageIO;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.chrome.ChromeDriver;

public class WebDriverDemo {
  static int pageHeight = 0;
  static int count = 0;
  static WebDriver driver;
  static List<BufferedImage> images = new LinkedList<>();

  public static void main(String[] args) {
    driver = new ChromeDriver();

    driver.get("http://automationpractice.com/");
    try {
      pageScrollable();

    } catch (WebDriverException | InterruptedException | IOException e) {
      e.printStackTrace();
    }

    driver.quit();
  }

  public static void pageScrollable() throws InterruptedException, IOException {

    JavascriptExecutor jse = (JavascriptExecutor) driver;

    // Find page height
    pageHeight = ((Number) jse.executeScript("return document.body.scrollHeight")).intValue();
    // Find current browser dimensions and isolate its height
    int browserSize = ((Number) jse.executeScript("return window.innerHeight")).intValue();
    System.out.println("Page height is: " + pageHeight + "\n");
    System.out.println("Browser height is: " + browserSize + "\n");

    int currentHeight = 0;
    System.out.println("Current scroll at: " + currentHeight);
    System.out.println("Page height is: " + pageHeight + "\n");

    // Scrolling logic
    while (pageHeight >= currentHeight) {
      screenShot();
      currentHeight += browserSize;
      jse.executeScript("window.scrollBy(0," + browserSize + ")", "");
      System.out.println("Current scroll now at: " + currentHeight);
    }

    BufferedImage result = null;
    Graphics2D g2d = null;
    int heightCurr = 0;
    System.out.println("Image count is " + images.size());
    for (int i = 0; i < images.size(); i++) {
      BufferedImage img = images.get(i);
      int imageHeight = 0;
      if (result == null) {
        System.out.println("Image height is " + img.getHeight()); // differs from browserSize
        imageHeight = pageHeight + images.size() * (img.getHeight() - browserSize);
        result = new BufferedImage(img.getWidth(), imageHeight, img.getType());
        g2d = result.createGraphics();
      }
      if (i == images.size() - 1) {
        g2d.drawImage(img, 0, imageHeight - img.getHeight(), null);
      } else {
        g2d.drawImage(img, 0, heightCurr, null);
        heightCurr += img.getHeight();
      }
    }
    g2d.dispose();
    ImageIO.write(result, "png", new File("screenshot.png"));
  }

  public static void screenShot() throws IOException, InterruptedException {
    byte[] scr = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
    BufferedImage img = ImageIO.read(new ByteArrayInputStream(scr));
    images.add(img);
  }
}

Unfortunately it does not deliver proper results with FireFox because of glitches in their Window.scrollBy implementation.