86

目前我正在尝试使用 Selenium WebDriver 捕获屏幕截图。但我只能获得整个页面的屏幕截图。但是,我想要的只是捕获页面的一部分,或者可能只是基于 ID 或任何特定元素定位器的特定元素。(例如,我希望捕获图像 id = "Butterfly" 的图片)

有没有办法按选定的项目或元素捕获屏幕截图?

4

23 回答 23

125

我们可以通过裁剪整个页面截图来获取元素截图,如下所示:

driver.get("http://www.google.com");
WebElement ele = driver.findElement(By.id("hplogo"));

// Get entire page screenshot
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
BufferedImage  fullImg = ImageIO.read(screenshot);

// Get the location of element on the page
Point point = ele.getLocation();

// Get width and height of the element
int eleWidth = ele.getSize().getWidth();
int eleHeight = ele.getSize().getHeight();

// Crop the entire page screenshot to get only element screenshot
BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), point.getY(),
    eleWidth, eleHeight);
ImageIO.write(eleScreenshot, "png", screenshot);

// Copy the element screenshot to disk
File screenshotLocation = new File("C:\\images\\GoogleLogo_screenshot.png");
FileUtils.copyFile(screenshot, screenshotLocation);
于 2012-12-12T07:09:32.280 回答
19

这是一个使用 Selenium webdriver 和 Pillow 的 Python 3 版本。该程序捕获整个页面的屏幕截图并根据其位置裁剪元素。元素图像将以 image.png 的形式提供。Firefox 支持直接使用 element.screenshot_as_png('image_name') 保存元素图像。

from selenium import webdriver
from PIL import Image

driver = webdriver.Chrome()
driver.get('https://www.google.co.in')

element = driver.find_element_by_id("lst-ib")

location = element.location
size = element.size

driver.save_screenshot("shot.png")

x = location['x']
y = location['y']
w = size['width']
h = size['height']
width = x + w
height = y + h

im = Image.open('shot.png')
im = im.crop((int(x), int(y), int(width), int(height)))
im.save('image.png')

更新

现在 chrome 还支持单个元素截图。因此,您可以直接捕获 Web 元素的屏幕截图,如下所示。

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.google.co.in')
image = driver.find_element_by_id("lst-ib").screenshot_as_png 
# or
# element = driver.find_element_by_id("lst-ib")
# element.screenshot_as_png("image.png")
于 2018-07-25T11:19:42.053 回答
11

Yandex 的 AShot 框架可用于在 Selenium WebDriver 脚本中截屏

  • 完整的网页
  • 网页元素

这个框架可以在https://github.com/yandex-qatools/ashot上找到。

截屏的代码非常简单:

整页

Screenshot screenshot = new AShot()
        .shootingStrategy(new ViewportPastingStrategy(1000))
        .takeScreenshot(driver);

ImageIO.write(screenshot.getImage(), "PNG", new File("c:\\temp\\results.png"));

特定的网络元素

Screenshot screenshot = new AShot()
        .takeScreenshot(driver, driver.findElement(By.xpath("(//div[@id='ct_search'])[1]")));
    
ImageIO.write(screenshot.getImage(), "PNG", new File("c:\\temp\\div_element.png"));

在本文中查看更多详细信息和更多代码示例。

于 2015-10-30T23:44:59.870 回答
9

Node.js中,我编写了以下代码,但它不是基于 selenium 的官方 WebDriverJS,而是基于SauceLabs's WebDriverWD.js和一个非常紧凑的名为 EasyImage 的图像

我只是想强调你不能真正截取元素的截图,但你应该首先截取整个页面的截图,然后选择你喜欢的页面部分并裁剪该特定部分:

browser.get(URL_TO_VISIT)
       .waitForElementById(dependentElementId, webdriver.asserters.isDisplayed, 3000)
       .elementById(elementID)
        .getSize().then(function(size) {
            browser.elementById(elementID)
                   .getLocation().then(function(location) {
                        browser.takeScreenshot().then(function(data) {
                            var base64Data = data.replace(/^data:image\/png;base64,/, "");
                            fs.writeFile(filePath, base64Data, 'base64', function(err) {
                                if (err) {
                                    console.log(err);
                                } 
                                else {
                                    cropInFile(size, location, filePath);
                                }
                                doneCallback();
                        });
                    });
                });
            }); 

而cropInFileFunction,是这样的:

var cropInFile = function(size, location, srcFile) {
    easyimg.crop({
            src: srcFile,
            dst: srcFile,
            cropwidth: size.width,
            cropheight: size.height,
            x: location.x,
            y: location.y,
            gravity: 'North-West'
        },
        function(err, stdout, stderr) {
            if (err) throw err;
        });
};
于 2014-04-15T14:41:06.613 回答
8

对于每个需要 C# 代码的人,下面是我的实现的简化版本。

public static void TakeScreenshot(IWebDriver driver, IWebElement element)
{
    try
    {
        string fileName = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".jpg";
        Byte[] byteArray = ((ITakesScreenshot)driver).GetScreenshot().AsByteArray;
        System.Drawing.Bitmap screenshot = new System.Drawing.Bitmap(new System.IO.MemoryStream(byteArray));
        System.Drawing.Rectangle croppedImage = new System.Drawing.Rectangle(element.Location.X, element.Location.Y, element.Size.Width, element.Size.Height);
        screenshot = screenshot.Clone(croppedImage, screenshot.PixelFormat);
        screenshot.Save(String.Format(@"C:\SeleniumScreenshots\" + fileName, System.Drawing.Imaging.ImageFormat.Jpeg));
    }
    catch (Exception e)
    {
        logger.Error(e.StackTrace + ' ' + e.Message);
    }
}
于 2016-06-15T09:25:00.180 回答
5

我在截图上浪费了很多时间,我想保存你的。我使用了 chrome + selenium + c#,结果非常糟糕。最后我写了一个函数:

driver.Manage().Window.Maximize();
             RemoteWebElement remElement = (RemoteWebElement)driver.FindElement(By.Id("submit-button")); 
             Point location = remElement.LocationOnScreenOnceScrolledIntoView;  

             int viewportWidth = Convert.ToInt32(((IJavaScriptExecutor)driver).ExecuteScript("return document.documentElement.clientWidth"));
             int viewportHeight = Convert.ToInt32(((IJavaScriptExecutor)driver).ExecuteScript("return document.documentElement.clientHeight"));

             driver.SwitchTo();

             int elementLocation_X = location.X;
             int elementLocation_Y = location.Y;

             IWebElement img = driver.FindElement(By.Id("submit-button"));

             int elementSize_Width = img.Size.Width;
             int elementSize_Height = img.Size.Height;

             Size s = new Size();
             s.Width = driver.Manage().Window.Size.Width;
             s.Height = driver.Manage().Window.Size.Height;

             Bitmap bitmap = new Bitmap(s.Width, s.Height);
             Graphics graphics = Graphics.FromImage(bitmap as Image);
             graphics.CopyFromScreen(0, 0, 0, 0, s);

             bitmap.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);

             RectangleF part = new RectangleF(elementLocation_X, elementLocation_Y + (s.Height - viewportHeight), elementSize_Width, elementSize_Height);

             Bitmap bmpobj = (Bitmap)Image.FromFile(filePath);
             Bitmap bn = bmpobj.Clone(part, bmpobj.PixelFormat);
             bn.Save(finalPictureFilePath, System.Drawing.Imaging.ImageFormat.Png); 
于 2013-07-03T12:13:29.783 回答
4

如果您不介意涉及磁盘 IO,Surya 的回答非常有用。如果您不愿意,那么这种方法可能更适合您

private Image getScreenshot(final WebDriver d, final WebElement e) throws IOException {
    final BufferedImage img;
    final Point topleft;
    final Point bottomright;

    final byte[] screengrab;
    screengrab = ((TakesScreenshot) d).getScreenshotAs(OutputType.BYTES);

    img = ImageIO.read(new ByteArrayInputStream(screengrab));

    //crop the image to focus on e
    //get dimensions (crop points)
    topleft = e.getLocation();
    bottomright = new Point(e.getSize().getWidth(),
                            e.getSize().getHeight());

    return img.getSubimage(topleft.getX(),
                           topleft.getY(),
                           bottomright.getX(),
                           bottomright.getY());
}

如果你愿意,你可以跳过声明screengrab,而是做

img = ImageIO.read(
    new ByteArrayInputStream(
        ((TakesScreenshot) d).getScreenshotAs(OutputType.BYTES)));

这更干净,但为了清楚起见,我把它留了下来。然后,您可以将其保存为文件将其放入 JPanel 中以随心所欲

于 2015-01-29T05:42:44.513 回答
4

蟒蛇 3

尝试使用 Selenium 3.141.0 和 chromedriver 73.0.3683.68,这可行,

from selenium import webdriver

chromedriver = '/usr/local/bin/chromedriver'
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument('window-size=1366x768')
chromeOptions.add_argument('disable-extensions')
cdriver = webdriver.Chrome(options=chromeOptions, executable_path=chromedriver)

cdriver.get('url')
element = cdriver.find_element_by_css_selector('.some-css.selector')

element.screenshot_as_png('elemenent.png')

无需获取完整图像并获取全屏图像的一部分。

创建Rohit 的答案时,这可能不可用。

于 2019-04-14T15:24:50.527 回答
3

我认为这里的大多数答案都是过度设计的。我这样做的方式是通过 2 个辅助方法,第一个等待基于任何选择器的元素;第二个是截图。

注意:我们将WebElement转换为一个TakesScreenshot实例,因此我们只专门捕获图像中的那个元素。如果您想要整个页面/窗口,您应该driver改为投射。

编辑:我忘了说我正在使用 Java 和 Selenium v​​3(但对于 v4 应该是相同的)

WebDriver driver = new FirefoxDriver(); // define this somewhere (or chrome etc)

public <T> T screenshotOf(By by, long timeout, OutputType<T> type) {
    return ((TakesScreenshot) waitForElement(by, timeout))
            .getScreenshotAs(type);
}

public WebElement waitForElement(By by, long timeout) {
    return new WebDriverWait(driver, timeout)
            .until(driver -> driver.findElement(by));
}

然后像这样截图你想要的任何东西:

long timeout = 5;   // in seconds
/* Screenshot (to file) based on first occurence of tag */
File sc = screenshotOf(By.tagName("body"), timeout, OutputType.FILE); 
/* Screenshot (in memory) based on CSS selector (e.g. first image in body
who's "src" attribute starts with "https")  */
byte[] sc = screenshotOf(By.cssSelector("body > img[href^='https']"), timeout, OutputType.BYTES);
于 2021-01-01T10:35:27.210 回答
2

这是 C# 的扩展函数:

public static BitmapImage GetElementImage(this IWebDriver webDriver, By by)
{
    var elements = webDriver.FindElements(by);
    if (elements.Count == 0)
        return null;

    var element = elements[0];
    var screenShot = (webDriver as ITakesScreenshot).GetScreenshot();
    using (var ms = new MemoryStream(screenShot.AsByteArray))
    {
        Bitmap screenBitmap;
        screenBitmap = new Bitmap(ms);
        return screenBitmap.Clone(
            new Rectangle(
                element.Location.X,
                element.Location.Y,
                element.Size.Width,
                element.Size.Height
            ),
            screenBitmap.PixelFormat
        ).ToBitmapImage();
    }
}

现在您可以使用它来拍摄任何元素的图像,如下所示:

var image = webDriver.GetElementImage(By.Id("someId"));
于 2017-10-26T08:20:25.853 回答
2

如果您正在寻找 JavaScript 解决方案,这是我的要点:

https://gist.github.com/silicon/4abcd9079a7d29cbb53ebee547b55fba

基本思路是一样的,先截屏,再裁剪。但是,我的解决方案不需要其他库,只需要纯 WebDriver API 代码。但是,副作用是它可能会增加测试浏览器的负载。

于 2017-09-22T21:55:43.297 回答
2
public void GenerateSnapshot(string url, string selector, string filePath)
    {
        using (IWebDriver driver = new ChromeDriver())
        {
            driver.Navigate().GoToUrl(url);
            var remElement = driver.FindElement(By.CssSelector(selector));
            Point location = remElement.Location;

            var screenshot = (driver as ChromeDriver).GetScreenshot();
            using (MemoryStream stream = new MemoryStream(screenshot.AsByteArray))
            {
                using (Bitmap bitmap = new Bitmap(stream))
                {
                    RectangleF part = new RectangleF(location.X, location.Y, remElement.Size.Width, remElement.Size.Height);
                    using (Bitmap bn = bitmap.Clone(part, bitmap.PixelFormat))
                    {
                        bn.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
                    }
                }
            }
            driver.Close();
        }
    }
于 2016-03-15T13:07:02.697 回答
1

c#代码:

public Bitmap MakeElemScreenshot( IWebDriver driver, WebElement elem)
{
    Screenshot myScreenShot = ((ITakesScreenshot)driver).GetScreenshot();

    Bitmap screen = new Bitmap(new MemoryStream(myScreenShot.AsByteArray));
    Bitmap elemScreenshot = screen.Clone(new Rectangle(elem.Location, elem.Size), screen.PixelFormat);

    screen.Dispose();

    return elemScreenshot;
}
于 2019-01-31T11:59:57.580 回答
1

考虑使用 needle - 自动视觉比较工具 https://github.com/bfirsh/needle,它具有允许截取特定元素(由 CSS 选择器选择)的内置功能。该工具适用于 Selenium 的 WebDriver,它是用 Python 编写的。

于 2017-03-01T15:01:18.863 回答
1

在为 Selenium 中的特定元素拍摄快照的功能下方。这里的驱动程序是一种WebDriver。

private static void getScreenshot(final WebElement e, String fileName) throws IOException {
  final BufferedImage img;
  final Point topleft;
  final Point bottomright;
  final byte[] screengrab;
  screengrab = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
  img = ImageIO.read(new ByteArrayInputStream(screengrab));
  topleft = e.getLocation();
  bottomright = new Point(e.getSize().getWidth(), e.getSize().getHeight());
  BufferedImage imgScreenshot= 
      (BufferedImage)img.getSubimage(topleft.getX(), topleft.getY(), bottomright.getX(), bottomright.getY());
  File screenshotLocation = new File("Images/"+fileName +".png");    
  ImageIO.write(imgScreenshot, "png", screenshotLocation);
 }
于 2017-07-02T06:56:05.460 回答
0

这是我的版本,在 C# 中,我基本上从 Brook 的回答中得到了大部分内容,并对其进行了修改以适合我的目的

public static byte[] GetElementImage(this IWebElement element)
    {
        var screenShot = MobileDriver.Driver.GetScreenshot();
        using (var stream = new MemoryStream(screenShot.AsByteArray))
        {
            var screenBitmap = new Bitmap(stream);
            var elementBitmap = screenBitmap.Clone(
                new Rectangle(
                    element.Location.X,
                    element.Location.Y,
                    element.Size.Width,
                    element.Size.Height
                ),
                screenBitmap.PixelFormat
            );
            var converter = new ImageConverter();
            return (byte[]) converter.ConvertTo(elementBitmap, typeof(byte[]));
        }
    }
于 2020-03-03T19:40:42.033 回答
0

对于 C#,下面的代码可以工作。

试试
{

IWebElement transactions = driver.FindElement(By.XPath(".//*[@id='some element']"));

截图 screenshot = ((ITakesScreenshot)driver).GetScreenshot();

string title = "某个标题";

screenshot.SaveAsFile(title, ScreenshotImageFormat.Jpeg);

} 捕捉(异常){

// 未找到元素时处理

}

于 2021-07-20T06:57:47.303 回答
0
using System.Drawing;
using System.Drawing.Imaging;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

public void ScreenshotByElement()
{
    IWebDriver driver = new FirefoxDriver();
    String baseURL = "www.google.com/"; //url link
    String filePath = @"c:\\img1.png";      

    driver.Navigate().GoToUrl(baseURL);
    var remElement = driver.FindElement(By.Id("Butterfly"));
    Point location = remElement.Location;

    var screenshot = (driver as FirefoxDriver).GetScreenshot();
    using (MemoryStream stream = new MemoryStream(screenshot.AsByteArray))
    {
        using (Bitmap bitmap = new Bitmap(stream))
        {
            RectangleF part = new RectangleF(location.X, location.Y, remElement.Size.Width, remElement.Size.Height);
            using (Bitmap bn = bitmap.Clone(part, bitmap.PixelFormat))
            {
                bn.Save(filePath, ImageFormat.Png);                        
            }
        }
    }
}
于 2016-12-08T02:45:51.680 回答
0

如果您在 chrome 中收到异常java.awt.image.RasterFormatException,或者您想将元素滚动到视图中,然后捕获屏幕截图。

这是来自@Surya 答案的解决方案。

        JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
        Long offsetTop = (Long) jsExecutor.executeScript("window.scroll(0, document.querySelector(\""+cssSelector+"\").offsetTop - 0); return document.querySelector(\""+cssSelector+"\").getBoundingClientRect().top;");

        WebElement ele = driver.findElement(By.cssSelector(cssSelector));

        // Get entire page screenshot
        File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        BufferedImage  fullImg = ImageIO.read(screenshot);

        // Get the location of element on the page
        Point point = ele.getLocation();

        // Get width and height of the element
        int eleWidth = ele.getSize().getWidth();
        int eleHeight = ele.getSize().getHeight();

        // Crop the entire page screenshot to get only element screenshot
        BufferedImage eleScreenshot= fullImg.getSubimage(point.getX(), Math.toIntExact(offsetTop),
                eleWidth, eleHeight);
        ImageIO.write(eleScreenshot, "png", screenshot);

        // Copy the element screenshot to disk
        File screenshotLocation = new File("c:\\temp\\div_element_1.png");
        FileUtils.copyFile(screenshot, screenshotLocation);
于 2018-11-26T12:52:48.983 回答
0

要截取特定元素的屏幕截图,您现在可以使用以下命令:

public void takeCanvasScreenshot(WebElement element, String imageName) {
   
   File screenshot = element.getScreenshotAs(OutputType.FILE);

   try {
       FileUtils.copyFile(screenshot, new File("src/main/resources/screenshots/" + imageName + ".png"));
   } catch (IOException e) {
       e.printStackTrace();
   }
}
于 2021-04-28T12:37:29.197 回答
-1

我正在使用@Brook 答案的修改版本,即使对于需要滚动页面的元素也能正常工作。

public void TakeScreenshot(string fileNameWithoutExtension, IWebElement element)
{
    // Scroll to the element if necessary
    var actions = new Actions(_driver);
    actions.MoveToElement(element);
    actions.Perform();
    // Get the element position (scroll-aware)
    var locationWhenScrolled = ((RemoteWebElement) element).LocationOnScreenOnceScrolledIntoView;
    var fileName = fileNameWithoutExtension + ".png";
    var byteArray = ((ITakesScreenshot) _driver).GetScreenshot().AsByteArray;
    using (var screenshot = new System.Drawing.Bitmap(new System.IO.MemoryStream(byteArray)))
    {
        var location = locationWhenScrolled;
        // Fix location if necessary to avoid OutOfMemory Exception
        if (location.X + element.Size.Width > screenshot.Width)
        {
            location.X = screenshot.Width - element.Size.Width;
        }
        if (location.Y + element.Size.Height > screenshot.Height)
        {
            location.Y = screenshot.Height - element.Size.Height;
        }
        // Crop the screenshot
        var croppedImage = new System.Drawing.Rectangle(location.X, location.Y, element.Size.Width, element.Size.Height);
        using (var clone = screenshot.Clone(croppedImage, screenshot.PixelFormat))
        {
            clone.Save(fileName, ImageFormat.Png);
        }
    }
}

这两个ifs 是必要的(至少对于 chrome 驱动程序),因为当需要滚动时,裁剪的大小超过了屏幕截图大小的 1 个像素。

于 2016-12-02T00:34:10.783 回答
-1

我遵循了来自@codeslord 的示例代码,但由于某种原因,我不得不以不同的方式访问我的屏幕截图数据:

 # Open the Firefox webdriver
 driver = webdriver.Firefox()
 # Find the element that you're interested in
 imagepanel = driver.find_element_by_class_name("panel-height-helper")
 # Access the data bytes for the web element
 datatowrite = imagepanel.screenshot_as_png
 # Write the byte data to a file
 outfile = open("imagepanel.png", "wb")
 outfile.write(datatowrite)
 outfile.close()

(使用 Python 3.7、Selenium 3.141.0 和 Mozilla Geckodriver 71.0.0.7222)

于 2020-02-04T18:44:30.807 回答
-1

我相信这对您不起作用,因为您使用 C# 并且我的解决方案包括一个 Java 库,但是也许其他人会发现它有帮助。

要捕获自定义屏幕截图,您可以使用 Shutterbug 库。为此目的的具体要求是:

Shutterbug.shootElement(driver, element).save();
于 2017-01-13T08:45:15.703 回答