Selenium WebDriver C# - 如何进行全页面截图

7
有人能帮我使用Selenium webdriver拍摄完整的网页截图吗?我的代码是c#/ Nunit。我当前使用的方法无法拍摄整个浏览器页面。
我正在使用以下代码来拍摄屏幕截图。
public void TakeScreenShot(IWebDriver webDriver,string testName,string className)
{          

string folderName = String.Format("{0}.{1}", className, testName);

// Create Screenshot folder
string createdFolderLocation = CreateFolder(folderName);

// Take the screenshot            
Screenshot ss = ((ITakesScreenshot)webDriver).GetScreenshot();            
string screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;

// Save the screenshot
ss.SaveAsFile((string.Format("{0}\\{1}",createdFolderLocation,testName + ".Jpeg")), System.Drawing.Imaging.ImageFormat.Jpeg);
ss.ToString();

}

请发布您当前正在使用的代码。 - Arran
你认为什么是完整的浏览器页面? - Anders
问题出在哪里?你的代码看起来很好。 - Arran
谢谢回复。 我无法看到浏览器的URL和其他顶部部分。 之前我能够使用Selenium RC获取整个页面。 - anil
你需要URL地址栏等等是为了什么呢? - Arran
在我们的应用程序中,URL 提供了一些有价值的信息来诊断测试失败。因此,如果我的屏幕截图也包含该信息,那就太好了。 - anil
10个回答

6

我最近开始使用它并且很喜欢,但有时似乎存在内存问题,并且在生成HTML报告时会卡住。 - rkkreddy

4
WebDriver定义的“全页”截图包括浏览器中显示的整个页面,但不包括浏览器的界面(URL地址栏、工具栏、窗口大小调整句柄等)。如果您不需要在截图中获取完整的DOM,则无需使用WebDriver来获取截图。您可以使用操作系统的API来处理这个问题。

1
感谢各位的回答。 - anil

2

我在我们的解决方案中使用了这个:

 public byte[] TakeScreenshot()
    {
      try
      {
        var getMaxSide = "return Math.max(document.body.scroll{0}, document.body.offset{0}, document.documentElement.client{0}, document.documentElement.scroll{0}, document.documentElement.offset{0})";
        var scrollHeight = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Height"));
        var scrollWidth = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Width"));
        Driver.Manage().Window.Size = new Size(int.Parse(scrollWidth.ToString()), int.Parse(scrollHeight.ToString()));
        return (Driver as ITakesScreenshot).GetScreenshot().AsByteArray;
      }
      catch
      {
        return Array.Empty<byte>();
      }
    }

然后,您可以使用该结果将其附加到 Allure 或 NUnit 测试结果中,例如:
 private void AttachScreenshot()
    {
      var screenshot = _browser?.TakeScreenshot();
      if (screenshot.Length > 0)
      {
        // add screenshot to test results
        var path = DateTime.Now.Ticks.ToString() + ".png";
        File.WriteAllBytes(path, screenshot);
        TestContext.AddTestAttachment(path, "screenshot");

        // attach screenshot to Allure report
        AllureLifecycle.Instance.AddAttachment("screenshot", "image/png", screenshot);
      }
    }

1

来自2017年的问候))!

如果页面大小大于屏幕大小 - 您可以使用PhantomJS驱动程序(PhantomJS下载页面)

var fileName = "test.png";
var size = new Size(800, 2000);
var url = "https://stackoverflow.com/";

using (var driver = new PhantomJSDriver())
{
    driver.Manage().Window.Size = size;
    driver.Navigate().GoToUrl(url);
    ((ITakesScreenshot)driver)
        .GetScreenshot()
        .SaveAsFile(fileName, ImageFormat.Png);

    driver.Close();
}

1
你可以尝试这个。
IWebDriver driver = new PhantomJSDriver();
driver.Navigate().GoToUrl("http://www.google.com");
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile("image.png", ImageFormat.Png);

这是使用Selenium WebDriver和PhantomJS进行截图的代码。如果你想使用Firefox或Chrome,只需将PhantomJSDriver()更改为你想使用的驱动程序即可。 - salih
@Salih,我已经成功使用((ITakesScreenshot)driver).GetScreenshot().SaveAsFile();方法进行屏幕截图,感谢您的分享! - Rick Johnson

1

在截屏之前,尝试将浏览器窗口的大小调整为非常大。我将大小设置为宽度减少10,高度减少10。尝试添加而不是减少。

    driver = new FirefoxDriver(firefoxProfile);

    if (Config.MAXIMIZE_BROWSER_WINDOW)
    {
        driver.Manage().Window.Size = new System.Drawing.Size(System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - 10, System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - 10);
    }

0

试试这个,希望它能正常工作。

public void TakeScreenshot(string SSName)
        {
            try
            {
                string path = "D:\\WorkSpace\\Screenshot\\";
                Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
                ss.SaveAsFile((path + SSName), System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }

0

更改浏览器高度并不总是有效。这是我使用的解决方案。它通过页面滚动并组合全屏截图来实现。

public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
    {
        Bitmap fullPageScreenshot = null;
        using (var fullMs = new MemoryStream((driver.GetScreenshot()).AsByteArray)) { 
            fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
        }
        var originalPageOffset = driver.GetPageOffset();

        var prevPageOffset = 0;
        var currentPageOffset = 0;
        var scrollLength = (int)(driver.Manage().Window.Size.Height / 1.5);
        while (fullPageScreenshot.Height < maxHeight)
        {
            prevPageOffset = driver.GetPageOffset().Y;
                       
            driver.ScrollPageBy(0, scrollLength);
            System.Threading.Thread.Sleep(500);

            currentPageOffset = driver.GetPageOffset().Y;

            if (prevPageOffset == currentPageOffset)
            {
                break;
            }
            var pageMovedBy = currentPageOffset - prevPageOffset;
            using (var ms = new MemoryStream(driver.GetScreenshot().AsByteArray))
            {
                using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
                {
                    var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));
                    var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);
                    fullPageScreenshot.Dispose();
                    fullPageScreenshot = newFullPage;
                }
            }
        }
        driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
        return fullPageScreenshot;
    }

    public static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
    {
        Bitmap nb = new Bitmap(r.Width, r.Height);
        using (Graphics g = Graphics.FromImage(nb))
        {
            g.DrawImage(b, -r.X, -r.Y);
            return nb;
        }
    }

    public static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
    {
        int w = Math.Max(source.Width, target.Width);
        int h = source.Height + target.Height + spacing;
        Bitmap bmp = new Bitmap(w, h);

        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.DrawImage(source, 0, 0);
            g.DrawImage(target, 0, source.Height + spacing);
        }

        return bmp;
    }

    public static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
    {
        driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
    }

    public static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
    {
        driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
    }

    public static Point GetPageOffset(this RemoteWebDriver driver)
    {
        var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
        var x = (long)offsetArray[0];
        var y = (long)offsetArray[1];
        return new Point((int)x, (int)y);
    }

0
我记得 ((ITakesScreenshot)webDriver).GetScreenshot(); 可以截取整个页面的屏幕截图,但如果你有一些ajax请求和其他加载元素,你可以添加滚动并在最后等待几秒钟,这样你就知道它已经截取了完全加载的页面截图。
        for (int second = 0;; second++)
        {
            if (second >= 4)
            {
                break;
            }

            ((IJavaScriptExecutor)Global.Driver).ExecuteScript("window.scrollBy(0,800)", string.Empty);
            Thread.Sleep(500);
        }

        Thread.Sleep(3000);

0
根据@Michal Kalous的答案,我创建了一个扩展类。这还考虑了当前在窗口中设置的字体大小和实际视口大小,并通过将body.style.overflowY设置为hidden来删除垂直滚动条。
用法
RemoteWebDriver driver = new EdgeDriver();
driver.SetViewportSize(1200, 1200);

driver.Navigate().GoToUrl("https://www.bikereview.info/en/ktm-1290-super-duke-rr-innerhalb-von-48-minuten-ausverkauft.html");
Image tempImage = driver.TakeFullPageScreenshot();
tempImage.Save(@"c:\full.png", ImageFormat.Png);
driver.Close();
driver.Quit();

扩展类

using System;
using System.Drawing;
using System.IO;
using OpenQA.Selenium.Remote;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using OpenQA.Selenium;

namespace TestRenderHtmlToPng
{


    public static class RemoteWebDriverExtensions
    {

        public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
        {

            //Screenshots depend on fontscaleing-property in windows
            double DpiScalingFactor = GetDpiScalingFactor();

            Bitmap fullPageScreenshot = null;
            using (var fullMs = new MemoryStream((driver.GetScreenshotOverflowHidden()).AsByteArray))
            {
                fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
            }
            var originalPageOffset = driver.GetPageOffset();

            var prevPageOffset = 0;
            var currentPageOffset = 0;
            var scrollLength = driver.GetWindowInnerHeight();

            while (fullPageScreenshot.Height < maxHeight)
            {
                prevPageOffset = driver.GetPageOffset().Y;

                driver.ScrollPageBy(0, scrollLength);
                System.Threading.Thread.Sleep(100);

                currentPageOffset = driver.GetPageOffset().Y;

                if (prevPageOffset == currentPageOffset)
                {
                    break;
                }
                var pageMovedBy = currentPageOffset - prevPageOffset;
                pageMovedBy = (int)(pageMovedBy * DpiScalingFactor);

                using (var ms = new MemoryStream(driver.GetScreenshotOverflowHidden().AsByteArray))
                {
                    Bitmap fullPageScreenshot1 = Image.FromStream(ms) as Bitmap;
                    using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
                    {
                        var s = driver.Manage().Window.Size;

                        var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));

                        var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);

                        fullPageScreenshot.Dispose();
                        fullPageScreenshot = newFullPage;
                    }
                }
            }
            driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
            return fullPageScreenshot;
        }



        private static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
        {
            Bitmap nb = new Bitmap(r.Width, r.Height);
            using (Graphics g = Graphics.FromImage(nb))
            {
                g.DrawImage(b, -r.X, -r.Y);
                return nb;
            }
        }

        private static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
        {
            int w = Math.Max(source.Width, target.Width);
            int h = source.Height + target.Height + spacing;
            Bitmap bmp = new Bitmap(w, h);

            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.DrawImage(source, 0, 0);
                g.DrawImage(target, 0, source.Height + spacing);
            }

            return bmp;
        }

        private static Screenshot GetScreenshotOverflowHidden(this RemoteWebDriver driver)
        {
            driver.ExecuteScript(@" document.body.style.overflowY = ""hidden"";");
            var s = driver.GetScreenshot();
            driver.ExecuteScript(@" document.body.style.overflowY = """";");
            return s;
        }

        private static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
        {
            driver.ExecuteScript(@"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
        }
        private static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
        {
            driver.ExecuteScript(@"window.scroll(arguments[0], arguments[1]);", x, y);
        }

        public static void SetViewportSize(this RemoteWebDriver driver, int width, int height)
        {
            var jsGetPadding = @"return [ window.outerWidth - window.innerWidth,window.outerHeight - window.innerHeight ];";
            var paddingArray = driver.ExecuteScript(jsGetPadding) as ReadOnlyCollection<object>;
            driver.Manage().Window.Size = new Size(width + int.Parse(paddingArray[0].ToString()), height + int.Parse(paddingArray[1].ToString()));

        }

        private static Point GetPageOffset(this RemoteWebDriver driver)
        {
            var offsetArray = driver.ExecuteScript(@"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
            var x = int.Parse(offsetArray[0].ToString());
            var y = int.Parse(offsetArray[1].ToString().Split(',')[0]);
            return new Point((int)x, (int)y);
        }
        private static int GetWindowInnerHeight(this RemoteWebDriver driver)
        {
            var Value = driver.ExecuteScript(@"return [window.innerHeight];") as ReadOnlyCollection<object>;
            return int.Parse(Value[0].ToString());

        }

        [DllImport("gdi32.dll")]
        private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
        public enum DeviceCap
        {
            VERTRES = 10,
            DESKTOPVERTRES = 117,

            // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
            // https://dev59.com/bG025IYBdhLWcg3weWAs
        }


        private static float GetDpiScalingFactor()
        {
            Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            IntPtr desktop = g.GetHdc();
            int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
            int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);

            float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;

            return ScreenScalingFactor; // 1.25 = 125%
        }

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接