Как сделать снимок экрана конкретного элемента, а не всей страницы с помощью Selenium Webdriver?


В настоящее время я пытаюсь сделать снимок экрана с помощью Selenium WebDriver. Но я могу получить только весь снимок экрана страницы. Однако я хотел просто захватить часть страницы или, возможно, только на определенном элементе на основе идентификатора или любого конкретного локатора элементов. (Например, я хочу захватить изображение с идентификатором изображения = "бабочка")

есть ли способ сделать снимок экрана по выбранному элементу или элементу?

15   57  

15 ответа:

мы можем получить скриншот элемента, обрезав весь скриншот страницы, как показано ниже:

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

на Node.js, Я написал следующий код, который работает, но он не основан на официальном WebDriverJS селена, но на основе SauceLabs's WebDriver:WD.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;
        });
};

фреймворк ASHOT от Яндекса можно использовать для снятия скриншотов в скриптах Selenium WebDriver для

  • полный веб-страницы
  • веб-элементы

эта структура может быть найдена на https://github.com/yandex-qatools/ashot.

код для снятия скриншотов очень простой:

СТРАНИЦЫ

screenshot = new AShot().shootingStrategy(
new ViewportPastingStrategy(1000)).takeScreenshot(driver);
ImageIO.write(screenshot.getImage(), "PNG", new File("c:\temp\results.png"));

КОНКРЕТНЫЙ ВЕБ-ЭЛЕМЕНТ

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

смотрите дополнительную информацию и больше примеров кода на в этой статье.

Я потратил много времени на скриншот, и я хочу, чтобы спасти тебя. Я использовал 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); 

для всех, кто просит код в 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);
    }
}

ответ Сурьи отлично работает, если вы не возражаете против включения дискового ввода-вывода. Если вы не хотите, то этот метод может быть лучше для вас

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 в свое удовольствие.

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

вот версия Python 3 с использованием Selenium webdriver и подушки. Эта программа захватывает скриншот всей страницы и обрезает элемент на основе его местоположения. Изображение элемента будет доступно в виде изображения.png

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')

рассмотрите возможность использования иглы-инструмента для автоматизированного визуального сравнения https://github.com/bfirsh/needle , который имеет встроенный функционал, позволяющий делать скриншоты конкретных элементов (выделенных селектором CSS). Инструмент работает на веб-драйвере Selenium, и он написан на Python.

ниже функции для создания моментального снимка определенного элемента в 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);
 }

Если вы ищете решение JavaScript, вот моя суть:

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

основная идея та же, сначала сделайте снимок экрана, а затем обрезайте его. Однако мое решение не потребует других библиотек, просто чистый код API WebDriver. Однако побочным эффектом является то, что он может увеличить нагрузку на ваш тестовый браузер.

вот функция расширения для 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"));
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);                        
            }
        }
    }
}

Я считаю, что это не будет работать для вас, как вы используете C# и мое решение включает в себя библиотеку Java, однако, возможно, другие найдут это полезным.

для захвата пользовательских скриншотов вы можете использовать библиотеку Shutterbug. Конкретный вызов для этой цели будет:

Shutterbug.shootElement(driver, element).save();

Я использую модифицированную версию ответа @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 пиксель размер скриншота, когда прокрутка была необходима.