专业网站建设品牌,十四年专业建站经验,服务6000+客户--广州京杭网络
免费热线:400-963-0016      微信咨询  |  联系我们

记录:c#中使用Selenium之二 整页截图

当前位置:网站建设 > 技术支持
资料来源:网络整理       时间:2023/2/14 0:40:43       共计:3613 浏览

1. 上文中介绍了怎么使用selenium及设置手机模式浏览,但发现只能截取屏幕部分图片,而之前网页端用webbrowser截图还可以,但手机端的话因为webbrowser是ie内核,导致页面样式杂乱。现改用selenium下面介绍整理的几种方式

    1.) selenium有默认的较为简单截图方式,只能截图屏幕区域,可满足简单的需求。


	
  1. //截图
  2. Screenshot screenShotFile = ((ITakesScreenshot)driver).GetScreenshot();
  3. string img_url = Environment.CurrentDirectory + @"\\test.jpg";
  4. screenShotFile.SaveAsFile(img_url, OpenQA.Selenium.ScreenshotImageFormat.Jpeg);

    2.) 创建继承ChromeDriver的类,执行js获取参数


	
  1. public class ChromeDriverEx : ChromeDriver
  2. {
  3. private const string SendChromeCommandWithResult = "sendChromeCommandWithResponse";
  4. private const string SendChromeCommandWithResultUrlTemplate = "/session/{sessionId}/chromium/send_command_and_get_result";
  5. public ChromeDriverEx(string chromeDriverDirectory, ChromeOptions options)
  6. : base(chromeDriverDirectory, options)
  7. {
  8. CommandInfo commandInfoToAdd = new CommandInfo(CommandInfo.PostCommand, SendChromeCommandWithResultUrlTemplate);
  9. this.CommandExecutor.CommandInfoRepository.TryAddCommand(SendChromeCommandWithResult, commandInfoToAdd);
  10. }
  11. public ChromeDriverEx(ChromeDriverService service, ChromeOptions options)
  12. : base(service, options)
  13. {
  14. CommandInfo commandInfoToAdd = new CommandInfo(CommandInfo.PostCommand, SendChromeCommandWithResultUrlTemplate);
  15. this.CommandExecutor.CommandInfoRepository.TryAddCommand(SendChromeCommandWithResult, commandInfoToAdd);
  16. }
  17. public Screenshot GetFullPageScreenshot()
  18. {
  19. string metricsScript = @"({
  20. width: Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)|0,
  21. height: Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)|0,
  22. deviceScaleFactor: window.devicePixelRatio || 1,
  23. mobile: typeof window.orientation !== 'undefined'
  24. })";
  25. Dictionary<string, object> metrics = this.EvaluateDevToolsScript(metricsScript);
  26. this.ExecuteChromeCommand("Emulation.setDeviceMetricsOverride", metrics);
  27. Dictionary<string, object> parameters = new Dictionary<string, object>();
  28. parameters["format"] = "png";
  29. parameters["fromSurface"] = true;
  30. object screenshotObject = this.ExecuteChromeCommandWithResult("Page.captureScreenshot", parameters);
  31. Dictionary<string, object> screenshotResult = screenshotObject as Dictionary<string, object>;
  32. string screenshotData = screenshotResult["data"] as string;
  33. this.ExecuteChromeCommand("Emulation.clearDeviceMetricsOverride", new Dictionary<string, object>());
  34. Screenshot screenshot = new Screenshot(screenshotData);
  35. return screenshot;
  36. }
  37. public object ExecuteChromeCommandWithResult(string commandName, Dictionary<string, object> commandParameters)
  38. {
  39. if (commandName == null)
  40. {
  41. throw new ArgumentNullException("commandName", "commandName must not be null");
  42. }
  43. Dictionary<string, object> parameters = new Dictionary<string, object>();
  44. parameters["cmd"] = commandName;
  45. parameters["params"] = commandParameters;
  46. Response response = this.Execute(SendChromeCommandWithResult, parameters);
  47. return response.Value;
  48. }
  49. private Dictionary<string, object> EvaluateDevToolsScript(string scriptToEvaluate)
  50. {
  51. Dictionary<string, object> parameters = new Dictionary<string, object>();
  52. parameters["returnByValue"] = true;
  53. parameters["expression"] = scriptToEvaluate;
  54. object evaluateResultObject = this.ExecuteChromeCommandWithResult("Runtime.evaluate", parameters);
  55. Dictionary<string, object> evaluateResultDictionary = evaluateResultObject as Dictionary<string, object>;
  56. Dictionary<string, object> evaluateResult = evaluateResultDictionary["result"] as Dictionary<string, object>;
  57. Dictionary<string, object> evaluateValue = evaluateResult["value"] as Dictionary<string, object>;
  58. return evaluateValue;
  59. }
  60. }

    此种调用方式为           


	
  1. //cdSvc参数为对象ChromeDriverService,也可直接将d://chromedriver/驱动所在地址作为参数传递
  2. ChromeDriverEx driver = new ChromeDriverEx(cdSvc, options);
  3. driver1.Url = "http://m.baidu.com";
  4. Screenshot screenshot = driver1.GetFullPageScreenshot();
  5. screenshot.SaveAsFile(Environment.CurrentDirectory + @"\FullPageScreenshot.png");

     3.) 在上面的方法的前提下,另一种GetFullPageScreenshot方式


	
  1. var filePath = Environment.CurrentDirectory + @"\FullPageScreenshot11.png";
  2. Dictionary<string, Object> metrics = new Dictionary<string, Object>();
  3. metrics["width"] = driver.ExecuteScript("return Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)");
  4. metrics["height"] = driver.ExecuteScript("return Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)");
  5. //返回当前显示设备的物理像素分辨率与 CSS 像素分辨率的比率
  6. metrics["deviceScaleFactor"] = driver.ExecuteScript("return window.devicePixelRatio");
  7. metrics["mobile"] = driver.ExecuteScript("return typeof window.orientation !== 'undefined'");
  8. driver.ExecuteChromeCommand("Emulation.setDeviceMetricsOverride", metrics);
  9. driver.GetScreenshot().SaveAsFile(filePath, ScreenshotImageFormat.Png);

 

参考:https://stackoverflow.com/questions/52043197/c-sharp-selenium-full-page-screenshot


I'd like to take a full page screenshot using C# with Selenium and ChromeDriver. Here: https://stackoverflow.com/a/45201692/5400125 I found an example how to do it in Java. I am trying to achieve this in C#, but I get an exception after page is loaded on the first call to sendEvaluate:

OpenQA.Selenium.WebDriverException: 'no such session (Driver info: chromedriver=2.41.578737 (49da6702b16031c40d63e5618de03a32ff6c197e),platform=Windows NT 10.0.17134 x86_64)'

public class ChromeDriverEx : ChromeDriver
{
    public ChromeDriverEx(string chromeDriverDirectory, ChromeOptions options)
        : base(chromeDriverDirectory, options, RemoteWebDriver.DefaultCommandTimeout)
    {
        var addCmd = this.GetType().BaseType
            .GetMethod("AddCustomChromeCommand", BindingFlags.NonPublic | BindingFlags.Instance);
        addCmd.Invoke(this,
            new object[] {"sendCommand", "POST", "/session/:sessionId/chromium/send_command_and_get_result"});
    }

    public void GetFullScreenshot()
    {
        Object metrics = sendEvaluate(
            @"({" +
            "width: Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)|0," +
            "height: Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)|0," +
            "deviceScaleFactor: window.devicePixelRatio || 1," +
            "mobile: typeof window.orientation !== 'undefined'" +
            "})");
    }

    private object sendEvaluate(string script)
    {
        var response = sendCommand("Runtime.evaulate",
            new Dictionary<string, object> {{"returnByValue", true}, {"expression", script}});
        return response;
    }

    private object sendCommand(string cmd, object param)
    {
        var r = this.Execute("sendCommand", new Dictionary<string, object> {{"cmd", cmd}, {"params", param}});
        return r.Value;
    }
}



And I call it like this:

 var opts = new ChromeOptions();
 opts.AddAdditionalCapability("useAutomationExtension", false);
 opts.AddArgument("disable-infobars");
 var driver = new ChromeDriverEx(".", opts);
 driver.Navigate().GoToUrl("https://stackoverflow.com/questions");
 driver.GetFullScreenshot();

I'm using Chrome 68 and ChromeDriver 2.41

This code works fine for me, in creating a subclass of ChromeDriver. Note that the code below is purposely written in a very, very verbose style, so as to clearly illustrate every piece of the solution. It could easily be written more concisely, depending on one's coding style and requirement for robust error handling. Moreover, in a future release, it will be unnecessary to create a method for executing a DevTools command that returns a result; such a method will already be part of the .NET bindings.

public class ChromeDriverEx : ChromeDriver
{
    private const string SendChromeCommandWithResult = "sendChromeCommandWithResponse";
    private const string SendChromeCommandWithResultUrlTemplate = "/session/{sessionId}/chromium/send_command_and_get_result";

    public ChromeDriverEx(string chromeDriverDirectory, ChromeOptions options)
        : base(chromeDriverDirectory, options)
    {
        CommandInfo commandInfoToAdd = new CommandInfo(CommandInfo.PostCommand, SendChromeCommandWithResultUrlTemplate);
        this.CommandExecutor.CommandInfoRepository.TryAddCommand(SendChromeCommandWithResult, commandInfoToAdd);
    }

    public Screenshot GetFullPageScreenshot()
    {
        // Evaluate this only to get the object that the
        // Emulation.setDeviceMetricsOverride command will expect.
        // Note that we can use the already existing ExecuteChromeCommand
        // method to set and clear the device metrics, because there's no
        // return value that we care about.
        string metricsScript = @"({
width: Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)|0,
height: Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)|0,
deviceScaleFactor: window.devicePixelRatio || 1,
mobile: typeof window.orientation !== 'undefined'
})";
        Dictionary<string, object> metrics = this.EvaluateDevToolsScript(metricsScript);
        this.ExecuteChromeCommand("Emulation.setDeviceMetricsOverride", metrics);

        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters["format"] = "png";
        parameters["fromSurface"] = true;
        object screenshotObject = this.ExecuteChromeCommandWithResult("Page.captureScreenshot", parameters);
        Dictionary<string, object> screenshotResult = screenshotObject as Dictionary<string, object>;
        string screenshotData = screenshotResult["data"] as string;

        this.ExecuteChromeCommand("Emulation.clearDeviceMetricsOverride", new Dictionary<string, object>());

        Screenshot screenshot = new Screenshot(screenshotData);
        return screenshot;
    }

    public object ExecuteChromeCommandWithResult(string commandName, Dictionary<string, object> commandParameters)
    {
        if (commandName == null)
        {
            throw new ArgumentNullException("commandName", "commandName must not be null");
        }

        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters["cmd"] = commandName;
        parameters["params"] = commandParameters;
        Response response = this.Execute(SendChromeCommandWithResult, parameters);
        return response.Value;
    }

    private Dictionary<string, object> EvaluateDevToolsScript(string scriptToEvaluate)
    {
        // This code is predicated on knowing the structure of the returned
        // object as the result. In this case, we know that the object returned
        // has a "result" property which contains the actual value of the evaluated
        // script, and we expect the value of that "result" property to be an object
        // with a "value" property. Moreover, we are assuming the result will be
        // an "object" type (which translates to a C# Dictionary<string, object>).
        Dictionary<string, object> parameters = new Dictionary<string, object>();
        parameters["returnByValue"] = true;
        parameters["expression"] = scriptToEvaluate;
        object evaluateResultObject = this.ExecuteChromeCommandWithResult("Runtime.evaluate", parameters);
        Dictionary<string, object> evaluateResultDictionary = evaluateResultObject as Dictionary<string, object>;
        Dictionary<string, object> evaluateResult = evaluateResultDictionary["result"] as Dictionary<string, object>;

        // If we wanted to make this actually robust, we'd check the "type" property
        // of the result object before blindly casting to a dictionary.
        Dictionary<string, object> evaluateValue = evaluateResult["value"] as Dictionary<string, object>;
        return evaluateValue;
    }
}

ou would use this code with something like the following:

ChromeOptions options = new ChromeOptions();
ChromeDriverEx driver = new ChromeDriverEx(@"C:\path\to\directory\of\chromedriver", options);
driver.Url = "https://stackoverflow.com/questions";

Screenshot screenshot = driver.GetFullPageScreenshot();
screenshot.SaveAsFile(@"C:\desired\screenshot\path\FullPageScreenshot.png");




Here is my sample of get Full Screen ScreenShot:

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




版权说明:
本网站凡注明“广州京杭 原创”的皆为本站原创文章,如需转载请注明出处!
本网转载皆注明出处,遵循行业规范,如发现作品内容版权或其它问题的,请与我们联系处理!
欢迎扫描右侧微信二维码与我们联系。
·上一条:Selenium WebDriver C#全屏幕截图使用ChromeDriver和FirefoxDriver | ·下一条:c#使用selenium+Chromedriver参数配置

Copyright © 广州京杭网络科技有限公司 2005-2025 版权所有    粤ICP备16019765号 

广州京杭网络科技有限公司 版权所有