如何使用Selenium WebDriver进行屏幕截图?

546
可以使用Selenium WebDriver来截取屏幕截图吗?
(注意:不是Selenium Remote Control)

使用WebDriver Wire Protocol可能只有一种方法来完成这个任务,但是没有人直接使用该协议。相反,人们使用不同的语言绑定/库来包装低级协议。有很多语言绑定,因此您需要说明要使用哪个。否则,就会有太多答案。 - oberlies
3
你正在使用哪种编程语言? - Ripon Al Wasim
你想截取整个页面还是特定元素的屏幕截图? - Ripon Al Wasim
是的,使用Selenium WebDriver可以截取整个页面或特定元素的屏幕截图。 - Ripon Al Wasim
52个回答

553

Java

可以的。以下示例是使用Java编写的:

WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com/");
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
// Now you can do whatever you need to do with it, for example copy somewhere
FileUtils.copyFile(scrFile, new File("c:\\tmp\\screenshot.png"));

34
如果源文件和目标文件可能不在同一个文件系统上,复制文件而不是重命名是个好主意。你不能跨越文件系统边界进行重命名(至少在Unix系统上是这样)。请注意,/tmp 常常位于自己的文件系统上,并且FirefoxDriver会将截图写入 /tmp 中。 - Tom Anderson
9
只针对失败的情况来做,有什么办法吗? - some_other_guy
6
值得注意的是,HtmlUnitDriver没有实现TakesScreenshot接口(请参阅http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/TakesScreenshot.html以获取支持的驱动程序列表)。但你可以保存为HTML。 - Wernight
10
使用FileUtils类需要导入哪个包?需要导入org.apache.commons.io包。 - Ripon Al Wasim
11
@RiponAlWasim 很可能是org.apache.commons.io.FileUtils - Ben
显示剩余13条评论

322

Python

每个WebDriver都有一个.save_screenshot(filename)方法。因此,对于Firefox,可以像这样使用:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get('http://www.google.com/')
browser.save_screenshot('screenie.png')

令人困惑的是,还存在一个名为.get_screenshot_as_file(filename)的方法,其功能与前者相同。

还有一些方法:.get_screenshot_as_base64()(用于在HTML中嵌入)和.get_screenshot_as_png()(用于检索二进制数据)。

注意,WebElements具有类似的.screenshot()方法,但只捕获选定的元素。


对于其他浏览器,请更换webdriver实例。如果您只想要包括状态的网站截图,请查看Usersnap - Gregor
@DavidRöthlisberger,这一切都很好,但是您的评论与我的答案无关。 - Corey Goldberg
2
@CoreyGoldberg 确实,与您的答案无关。但是我的旧脚本使用了较旧的FF,并且它确实获取了整个页面,而不仅仅是视口。在他们将其更改为标准后,现在只有视口。因此,我想帮助遇到同样问题的人。是的,固定元素在滚动/拼接时确实很麻烦! - Martin Krung
有没有一种方法可以更改/设置输出文件扩展名? - Ahsan Roy
3
还有一件事对我帮助很大,如果你需要改变图像的尺寸,只需在截屏之前使用driver.set_window_size(1366, 728)来设置窗口大小即可。 - srdg
显示剩余4条评论

119

C#

public void TakeScreenshot()
{
    try
    {            
        Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
        ss.SaveAsFile(@"D:\Screenshots\SeleniumTestingScreenshot.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        throw;
    }
}

10
完美运作。 注意:它截取的是屏幕截图而不是页面截图。 - ljgww
你的意思是它会获取桌面和所有内容吗?还是仅仅获取视口? - vtortola
它只会获取驱动程序范围内的内容,这是为了允许多个并行测试同时进行。请注意,如果您的驱动程序主窗口焦点具有滚动条或超过单个页面,则不会缩小视图。 - Ben
3
更新为SaveAsFile(string path, ScreenshotImageFormat format)方法 ScreenshotImageFormat.Jpeg表示JPEG格式。 - Kieran
1
这对我有效!我正在使用来自Graphics命名空间的CopyFromScreen。上述解决方案的优点是,当从TFS以无头方式调用代码时,它可以正常工作。我的旧CopyFromScreen方法仅在从Visual Studio运行selenium测试时工作,但从未在我的TFS运行测试中工作过。 - Ewan
错误 CS1069:在命名空间 'System.Drawing.Imaging' 中找不到类型名称 'ImageFormat'。该类型已转发到程序集 'System.Drawing.Common,Version=0.0.0.0,Culture=neutral,PublicKeyToken=cc7b13ffcd2ddd51'。请考虑添加对该程序集的引用。(CS1069) (xUnit_MSSO) - BSUK

86

JavaScript(Selenium-Webdriver)

driver.takeScreenshot().then(function(data){
   var base64Data = data.replace(/^data:image\/png;base64,/,"")
   fs.writeFile("out.png", base64Data, 'base64', function(err) {
        if(err) console.log(err);
   });
});

3
类似于Browserstack的描述方式:http://www.browserstack.com/automate/node#enhancements-screenshots - Mike Causer
在 data.replace 中,括号里面具体做了什么? - John Demetriou
@JohnDemetriou,data是在调用时将创建的对象或变量的名称。如果您愿意,可以将其称为“var1”。您应该查看takeScreenshot()函数以了解它的确切含义。可能是使用canvas从javascript渲染的二进制图像。它可以是dom,在呈现之前。请深入研究。 - m3nda

71

Ruby

require 'rubygems'
require 'selenium-webdriver'

driver = Selenium::WebDriver.for :ie
driver.get "https://www.google.com"
driver.save_screenshot("./screen.png")

有更多的文件类型和选项可用,你可以在文件takes_screenshot.rb中查看。


使用Selenium Grid 2对我来说运行良好。脚本和中心在OS X Snow Leopard上运行;节点在RedHat EL 4上,在Xvfb下使用Firefox 3.6.18。 - MarkD
2
有没有办法截取整个页面的屏幕截图,而不仅仅是可见区域? - Arihant Godha
2
默认情况下,整个页面都会被占用。至少要使用 headlessFirefox - Ashley
为什么 driver.get 不需要括号,但是 driver.save_screenshot 需要? - Peter Mortensen
@PeterMortensen - 我不确定,而且我已经很久没有使用Ruby了,所以我不记得它们之间是否有任何功能上的区别...我的直觉说它们是相同的...但出于安全原因,我建议使用完整的括号。 - sirclesam

38

Java

我已解决此问题。您可以增强RemoteWebDriver,使其具备代理驱动程序实现的所有接口:

WebDriver augmentedDriver = new Augmenter().augment(driver);
((TakesScreenshot)augmentedDriver).getScreenshotAs(...); // It works this way

如果这样做,那么难道不需要将屏幕截图复制到一个带有线程ID的文件名中吗?这样您就可以知道哪些线程/实例抛出了屏幕截图。否则,在一个网格节点上多个浏览器实例会相互覆盖彼此的屏幕截图。 - djangofan
1
我想指出的是,只有使用无界面ChromeDriver才能让我成功解决这个问题。 - rado

34

PHP (PHPUnit)

它使用 PHPUnit_Selenium 扩展版本 1.2.7:

class MyTestClass extends PHPUnit_Extensions_Selenium2TestCase {
    ...
    public function screenshot($filepath) {
        $filedata = $this->currentScreenshot();
        file_put_contents($filepath, $filedata);
    }

    public function testSomething() {
        $this->screenshot('/path/to/screenshot.png');
    }
    ...
}

哇塞!我想更多地了解这个。Selenium对我来说很新,我正在寻找一个CLI解决方案,在许多浏览器和操作系统上创建屏幕截图以进行视觉测试。 - pythonian29033

31

C#

public Bitmap TakeScreenshot(By by) {
    // 1. Make screenshot of all screen
    var screenshotDriver = _selenium as ITakesScreenshot;
    Screenshot screenshot = screenshotDriver.GetScreenshot();
    var bmpScreen = new Bitmap(new MemoryStream(screenshot.AsByteArray));

    // 2. Get screenshot of specific element
    IWebElement element = FindElement(by);
    var cropArea = new Rectangle(element.Location, element.Size);
    return bmpScreen.Clone(cropArea, bmpScreen.PixelFormat);
}

19

Java

public String captureScreen() {
    String path;
    try {
        WebDriver augmentedDriver = new Augmenter().augment(driver);
        File source = ((TakesScreenshot)augmentedDriver).getScreenshotAs(OutputType.FILE);
        path = "./target/screenshots/" + source.getName();
        FileUtils.copyFile(source, new File(path)); 
    }
    catch(IOException e) {
        path = "Failed to capture screenshot: " + e.getMessage();
    }
    return path;
}

你用了哪个驱动程序?new Augmenter().augment(driver); - kozla13
需要解释一下。您可以编辑您的答案不要包含“编辑:”、“更新:”或类似内容)。 - Peter Mortensen

13

Jython

import org.openqa.selenium.OutputType as OutputType
import org.apache.commons.io.FileUtils as FileUtils
import java.io.File as File
import org.openqa.selenium.firefox.FirefoxDriver as FirefoxDriver

self.driver = FirefoxDriver()
tempfile = self.driver.getScreenshotAs(OutputType.FILE)
FileUtils.copyFile(tempfile, File("C:\\screenshot.png"))

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