Selenium WebDriver C# 使用 ChromeDriver 和 FirefoxDriver 的完整网站截图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16795458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 07:47:22  来源:igfitidea点击:

Selenium WebDriver C# Full Website Screenshots With ChromeDriver and FirefoxDriver

c#seleniumwebdriverscreenshotselenium-chromedriver

提问by user2429052

When I take screenshots with ChromeDriver I get screens with the size of my viewport.
When I take screenshots with FirefoxDriver I get what I want, which is a full screen print of a website.

当我使用 ChromeDriver 截取屏幕截图时,我会得到与我的视口大小相同的屏幕。
当我使用 FirefoxDriver 截取屏幕截图时,我得到了我想要的内容,即网站的全屏打印。

ChromeDriver is declared like this:

ChromeDriver 声明如下:

IWebDriver driver = new ChromeDriver();

FirefoxDriver is declared like this:

FirefoxDriver 声明如下:

IWebDriver driver = new FirefoxDriver();

Both drivers execute identical code:

两个驱动程序都执行相同的代码:

driver.Manage().Window.Maximize();
driver.Navigate().GoToUrl(url);//url is a string variable
ITakesScreenshot screenshotDriver = driver as ITakesScreenshot;
Screenshot screenshot = screenshotDriver.GetScreenshot();
screenshot.SaveAsFile("c:/test.png", ImageFormat.Png);

ChromeDriver's test.png is of 1920x1099 resolution and contains only the browser viewport.
FirefoxDriver's test.png is of 1903x16559 resolution and contains the whole page.

ChromeDriver 的 test.png 分辨率为 1920x1099,仅包含浏览器视口。
FirefoxDriver 的 test.png 分辨率为 1903x16559,包含整个页面。

I know that GetScreenshot()method doesn't return identical resolution sizes because it has slightly different implementations in IEDriver, FirefoxDriver, OperaDriver, ChromeDriver.

我知道该GetScreenshot()方法不会返回相同的分辨率大小,因为它在 IEDriver、FirefoxDriver、OperaDriver、ChromeDriver 中的实现略有不同。

My questions are:

我的问题是:

  1. Why is there such difference between ChromeDriver's and FirefoxDriver's .GetScreenshot()method, even tho they use an identical interface (ITakesScreenshot)?

  2. Is there a way to make ChromeDriver's GetScreenshot()method return the whole webpage screen instead of just the viewport?

  1. 为什么 ChromeDriver 和 FirefoxDriver 的.GetScreenshot()方法之间存在如此大的差异,即使它们使用相同的界面 (ITakesScreenshot)?

  2. 有没有办法让 ChromeDriver 的GetScreenshot()方法返回整个网页屏幕而不仅仅是视口?

回答by DeveloperInDevelopment

It appears as though full-screen screenshots are not yet implemented in the ChromeDriver, due to some inaccuracies in its previous implementation.

由于之前的实现中存在一些不准确之处,ChromeDriver 中似乎尚未实现全屏屏幕截图。

Source: https://code.google.com/p/chromedriver/issues/detail?id=294

来源:https: //code.google.com/p/chromedriver/issues/detail?id=294

I have recently written a Selenium based application to test an Internet Explorer UI and found that:

我最近编写了一个基于 Selenium 的应用程序来测试 Internet Explorer UI,发现:

  1. Taking screenshots with selenium was not as quick as using .NET, and
  2. Selenium is unable to take screenshots when dialog boxes are present. This was a major drawback, as I needed to identify unexpected dialogs during interaction with the pages.
  1. 使用 selenium 截取屏幕截图不如使用 .NET 快,而且
  2. 当出现对话框时,Selenium 无法截取屏幕截图。这是一个主要缺点,因为我需要在与页面交互期间识别意外的对话框。

Investigate using the Graphics.CopyFromScreen method in System.Drawing as an alternative solution until the feature is implemented in Chrome. Once you have tried .the Net approach however, I don't think you will look back =]

使用 System.Drawing 中的 Graphics.CopyFromScreen 方法作为替代解决方案进行调查,直到该功能在 Chrome 中实现。但是,一旦您尝试过 .the Net 方法,我认为您不会回头看 =]

回答by Roemer

I stumbled accross the same problem and ChromeDriver2 just does not support it.

我偶然发现了同样的问题,ChromeDriver2 只是不支持它。

So I created a little script which scrolls thru the page, takes screenshots and stitches everything together.

所以我创建了一个滚动页面的小脚本,截取屏幕截图并将所有内容拼接在一起。

You can find the script in my blog post here: http://dev.flauschig.ch/wordpress/?p=341

您可以在我的博客文章中找到该脚本:http: //dev.flauschig.ch/wordpress/?p=341

回答by S.Roshanth

we can't get the entire page screenshot with ChromeDriver2, we need to go for manual implementation.I have modified a method with is available in a blog which works fine with ChromeDriver.

我们无法使用 ChromeDriver2 获取整个页面的屏幕截图,我们需要手动实现。我修改了一个博客中提供的方法,该方法适用于 ChromeDriver。

use this method as following :

使用此方法如下:

private IWebDriver _driver = new ChromeDriver(CHROME_DRIVER_PATH);
screenshot.SaveAsFile(saveFileName, ImageFormat.Jpeg);

public Bitmap GetEntereScreenshot()
    {

        Bitmap stitchedImage = null;
        try
        {
            long totalwidth1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return document.body.offsetWidth");//documentElement.scrollWidth");

            long totalHeight1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return  document.body.parentNode.scrollHeight");

            int totalWidth = (int)totalwidth1;
            int totalHeight = (int)totalHeight1;

            // Get the Size of the Viewport
            long viewportWidth1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return document.body.clientWidth");//documentElement.scrollWidth");
            long viewportHeight1 = (long)((IJavaScriptExecutor)_driver).ExecuteScript("return window.innerHeight");//documentElement.scrollWidth");

            int viewportWidth = (int)viewportWidth1;
            int viewportHeight = (int)viewportHeight1;


        // Split the Screen in multiple Rectangles
        List<Rectangle> rectangles = new List<Rectangle>();
        // Loop until the Total Height is reached
        for (int i = 0; i < totalHeight; i += viewportHeight)
        {
            int newHeight = viewportHeight;
            // Fix if the Height of the Element is too big
            if (i + viewportHeight > totalHeight)
            {
                newHeight = totalHeight - i;
            }
            // Loop until the Total Width is reached
            for (int ii = 0; ii < totalWidth; ii += viewportWidth)
            {
                int newWidth = viewportWidth;
                // Fix if the Width of the Element is too big
                if (ii + viewportWidth > totalWidth)
                {
                    newWidth = totalWidth - ii;
                }

                // Create and add the Rectangle
                Rectangle currRect = new Rectangle(ii, i, newWidth, newHeight);
                rectangles.Add(currRect);
            }
        }

        // Build the Image
        stitchedImage = new Bitmap(totalWidth, totalHeight);
        // Get all Screenshots and stitch them together
        Rectangle previous = Rectangle.Empty;
        foreach (var rectangle in rectangles)
        {
            // Calculate the Scrolling (if needed)
            if (previous != Rectangle.Empty)
            {
                int xDiff = rectangle.Right - previous.Right;
                int yDiff = rectangle.Bottom - previous.Bottom;
                // Scroll
                //selenium.RunScript(String.Format("window.scrollBy({0}, {1})", xDiff, yDiff));
                ((IJavaScriptExecutor)_driver).ExecuteScript(String.Format("window.scrollBy({0}, {1})", xDiff, yDiff));
                System.Threading.Thread.Sleep(200);
            }

            // Take Screenshot
            var screenshot = ((ITakesScreenshot)_driver).GetScreenshot();

            // Build an Image out of the Screenshot
            Image screenshotImage;
            using (MemoryStream memStream = new MemoryStream(screenshot.AsByteArray))
            {
                screenshotImage = Image.FromStream(memStream);
            }

            // Calculate the Source Rectangle
            Rectangle sourceRectangle = new Rectangle(viewportWidth - rectangle.Width, viewportHeight - rectangle.Height, rectangle.Width, rectangle.Height);

            // Copy the Image
            using (Graphics g = Graphics.FromImage(stitchedImage))
            {
                g.DrawImage(screenshotImage, rectangle, sourceRectangle, GraphicsUnit.Pixel);
            }

            // Set the Previous Rectangle
            previous = rectangle;
        }
        }
        catch (Exception ex)
        {
            // handle
        }
        return stitchedImage;
    }

回答by Lachlan Goodhew-Cook

I cleaned up @Selvantharajah Roshanth's answer and added a check so that it won't try to stitch together screenshots that already fit in the viewport.

我清理了@Selvantharajah Roshanth 的答案并添加了一个检查,这样它就不会尝试将已经适合视口的屏幕截图拼接在一起。

public Image GetEntireScreenshot()
{
    // Get the total size of the page
    var totalWidth = (int) (long) ((IJavaScriptExecutor) driver).ExecuteScript("return document.body.offsetWidth"); //documentElement.scrollWidth");
    var totalHeight = (int) (long) ((IJavaScriptExecutor) driver).ExecuteScript("return  document.body.parentNode.scrollHeight");
    // Get the size of the viewport
    var viewportWidth = (int) (long) ((IJavaScriptExecutor) driver).ExecuteScript("return document.body.clientWidth"); //documentElement.scrollWidth");
    var viewportHeight = (int) (long) ((IJavaScriptExecutor) driver).ExecuteScript("return window.innerHeight"); //documentElement.scrollWidth");

    // We only care about taking multiple images together if it doesn't already fit
    if (totalWidth <= viewportWidth && totalHeight <= viewportHeight)
    {
        var screenshot = driver.TakeScreenshot();
        return ScreenshotToImage(screenshot);
    }
    // Split the screen in multiple Rectangles
    var rectangles = new List<Rectangle>();
    // Loop until the totalHeight is reached
    for (var y = 0; y < totalHeight; y += viewportHeight)
    {
        var newHeight = viewportHeight;
        // Fix if the height of the element is too big
        if (y + viewportHeight > totalHeight)
        {
            newHeight = totalHeight - y;
        }
        // Loop until the totalWidth is reached
        for (var x = 0; x < totalWidth; x += viewportWidth)
        {
            var newWidth = viewportWidth;
            // Fix if the Width of the Element is too big
            if (x + viewportWidth > totalWidth)
            {
                newWidth = totalWidth - x;
            }
            // Create and add the Rectangle
            var currRect = new Rectangle(x, y, newWidth, newHeight);
            rectangles.Add(currRect);
        }
    }
    // Build the Image
    var stitchedImage = new Bitmap(totalWidth, totalHeight);
    // Get all Screenshots and stitch them together
    var previous = Rectangle.Empty;
    foreach (var rectangle in rectangles)
    {
        // Calculate the scrolling (if needed)
        if (previous != Rectangle.Empty)
        {
            var xDiff = rectangle.Right - previous.Right;
            var yDiff = rectangle.Bottom - previous.Bottom;
            // Scroll
            ((IJavaScriptExecutor) driver).ExecuteScript(String.Format("window.scrollBy({0}, {1})", xDiff, yDiff));
        }
        // Take Screenshot
        var screenshot = driver.TakeScreenshot();
        // Build an Image out of the Screenshot
        var screenshotImage = ScreenshotToImage(screenshot);
        // Calculate the source Rectangle
        var sourceRectangle = new Rectangle(viewportWidth - rectangle.Width, viewportHeight - rectangle.Height, rectangle.Width, rectangle.Height);
        // Copy the Image
        using (var graphics = Graphics.FromImage(stitchedImage))
        {
            graphics.DrawImage(screenshotImage, rectangle, sourceRectangle, GraphicsUnit.Pixel);
        }
        // Set the Previous Rectangle
        previous = rectangle;
    }
    return stitchedImage;
}

private static Image ScreenshotToImage(Screenshot screenshot)
{
    Image screenshotImage;
    using (var memStream = new MemoryStream(screenshot.AsByteArray))
    {
        screenshotImage = Image.FromStream(memStream);
    }
    return screenshotImage;
}