Как получить скриншот полной веб-страницы, используя Selenium и Java?

Как сделать скриншот для всей веб-страницы, а не только частичной сверху, используя Selenium WebDriver?

Мой Java-код Selenium WebDriver выглядит следующим образом:

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));

Есть идеи?

13 ответов

Решение

Короткий ответ - НЕТ, ВЫ НЕ МОЖЕТЕ (подробное объяснение ниже). Но то, что вы можете сделать, это максимально использовать область просмотра вашего устройства (монитора).

Итак, запустите ваш экземпляр браузера (драйвер), используя ChromeOptions(), который является методом для настройки возможностей ChromeDriver. Мы можем сделать следующее:

  • развернуть окно (используя --start-maximized переключатель);
  • перейти на полный экран (F11 ключ в Windows, Control+Cmd+F на Mac, используя --start-fullscreen переключатель).
  • Примечание: полный список ключей командной строки Chrome можно найти здесь.

Ваш код должен выглядеть так:

// Setting your Chrome options (Desired capabilities)
ChromeOptions options = new ChromeOptions();
options.add_argument('--start-maximized');
options.add_argument('--start-fullscreen');

// Creating a driver instance with the previous capabilities
WebDriver driver = new ChromeDriver(options);

// Load page & take screenshot of full-screen page
driver.get("http://google.com");
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);

Теперь по поводу проблемы полной страницы, все драйверы (chromedriver, geckodriver, IEDriver, EdgeDriver и т. д.) внедряем стандарт WebDriver W3C. Таким образом, они зависят от того, как команда WebDriver хочет показать функциональность различных функций, в нашем случае, "Снимок экрана".

Если вы читаете определение, оно четко гласит следующее:

Команда Take Screenshot делает снимок экрана VIEWPORT контекста верхнего уровня.

Устаревшие версии, некоторые драйверы могли создавать снимок экрана на всю страницу (подробнее об этом здесь), например старый FirefoxDriver, IEDriver и т. Д. Это уже не так, поскольку все они теперь реализуют (буквально) WebDriver Стандарт W3C.

Теперь есть простой способ сделать это с помощью Selenium 4 и Firefox.

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

Другие браузеры не поддерживают getFullPageScreenshotAs() еще.

Похоже, эта статья, в которой говорится, что AShot мне подходит. Кроме того, я успешно встроил полный снимок экрана в отчет Cucumber со следующим кодом

    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();
        }
    }

Вот как это сделать с помощью DevTools + Chromedriver:

        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);
  }

Я нашел учебник http://www.softwaretestingmaterial.com/how-to-capture-full-page-screenshot-using-selenium-webdriver/ Для пользователей maven: помните о добавлении зависимости с https://mvnrepository.com/artifact/ru.yandex.qatools.ashot/ashot При тестировании этого скрипта у меня есть большие картинки, которые нельзя открыть в браузере (слишком большие или сломанные).

Так может кто-нибудь знает какой-нибудь скрипт, на котором фокусная страница находится на последнем использованном локаторе?

Вот мой пример получения полноэкранного снимка экрана с помощью C#, но просто измените:

            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();

Можно запустить Chrome в режиме без заголовка, а затем установить размер окна на ту же высоту, что и тело страницы.

Поскольку высота вашего безголового браузера не зависит от размера вашего монитора, вы можете использовать этот безголовый режим для получения полноразмерных снимков экрана, поскольку они отображаются в браузере Chrome.

Главный ответ на запуск Chrome без головы с селеном, похоже, показывает правильный способ запустить Chrome в режиме без головы с помощью java. Я работаю с привязками Python, но ответ очень похож на то, что делаю я.

Это важная часть. Этот код должен быть выполнен до того, как вы запустите экземпляр ChromeDriver.

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

ChromeDriver driver = new ChromeDriver(chromeOptions);

Если запуск Chrome в безголовом браузере не является жизнеспособным вариантом, вам придется использовать Firefox или IE. Оба этих браузера предоставят вам полный скриншот.

Код Java без использования сторонней библиотеки:

      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));

Для некоторых страниц мне нужно сделать скриншот начала и конца страницы. Поэтому я использую, чтобы сделать 2 скриншота:

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));

Вы можете использовать Phantomjs для достижения этой цели.

Вот мой код Java:

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();
        }


    }
}

Таким образом, вы можете получить скриншот полной веб-страницы Phantomjs. Когда вы используете Phantomjs для получения полного скриншота, вам необходимо сначала загрузить Phantomjs. Затем запустите скрипт Phantomjs для скриншота. Подробнее об этом вы можете сослаться на http://phantomjs.org/.

Это самое простое решение, которое я нашел, которое, я думаю, должно работать в большинстве случаев:

В безголовом режиме вы можете установить область просмотра практически любого размера, который вы хотите, независимо от любого существующего физического размера экрана. Например:

          final ChromeOptions options = new ChromeOptions().setHeadless(true).addArguments("window-size=1200,3000");
    driver = new RemoteWebDriver(remoteAddress, options);

Обратите внимание, что вы можете использовать большую высоту, чтобы попытаться уместить всю страницу.

Ни один из описанных здесь вариантов не работал у меня в моей среде (go lang, chromedriver, реализация веб-драйвера fedesog). В конце концов мне пришло в голову уменьшить масштаб! Этот подход может работать для не слишком длинных страниц, для которых имеет смысл уменьшить масштаб.

Я думаю, что это может быть актуально для java или любого другого языка, использующего селен, поэтому размещаю его здесь для всех, кто сталкивается с этой проблемой на любом языке программирования :) Следующий фрагмент кода javascript позволяет установить уровень масштабирования:

      document.body.style.zoom = '0.5'

Где 0,5 — это желаемый уровень масштабирования. Его можно рассчитать динамически на основе фактического размера страницы, который можно получить с помощью:

      document.body.scrollHeight

и

      document.body.scrollWidth

как упомянуто выше, и выполняется как:

      webDriver.executeScript(...)

в java или

      session.ExecuteScript(...)

в golang с использованием fedesog или аналогичной среды веб-драйвера

File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("c:\\RESULT_FILENAME.png"));

Попробуй это

Другие вопросы по тегам