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


83

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

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


1
AFAIK, средство предназначено только для захвата всей страницы. У нас нет функции снимка экрана, которая принимает на вход идентификатор или имя элемента.
Hemanth

Кто-нибудь может сказать мне, что такое вызов метода для BUfferedImage в С #? Я не нашел похожего метода, связанного с этим.
fj123

Ответы:


118

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

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

Спасибо за ответ. Однако почему мой webdriver отличается от вашего. он использует IWebDriver, ITakeScreenshot, и нет OutputType.FILE и BufferedImage ... я использую устаревшую версию webdriver selenium?
fj123

Вы используете привязку веб-драйвера C #?
Сурья

Да, я так думаю. Раньше я использовал RC, а в последнее время просто перехожу на использование веб-драйвера.
fj123

Эта реализация предназначена для привязки Java. Эта концепция должна работать и для C #. Но я плохо разбираюсь в языке C #. Вам нужно использовать эквивалентные библиотеки C # (BufferedImage, ImageIO ...)
Сурья

4
Приведенный выше код не работает в Chrome. Исключение java.awt.image.RasterFormatException: (y + height) вне растра было выброшено в строке BufferedImage eleScreenshot = fullImg.getSubimage (point.getX (), point.getY (), eleWidth, eleHeight);
Рипон Аль Васим

14

Вот версия Python 3 с использованием Selenium webdriver и Pillow. Эта программа делает снимок экрана всей страницы и обрезает элемент в зависимости от его местоположения. Изображение элемента будет доступно как 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 также поддерживает скриншоты отдельных элементов. Таким образом, вы можете напрямую сделать снимок экрана веб-элемента, как показано ниже.

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

4
Я почти уверен, что element.sizeэто указано в точках, тогда как снимок экрана, созданный с помощью, driver.save_screenshotимеет размеры в пикселях. Если на вашем экране соотношение пикселей к точкам отличается от 1 (например, у Retina MacBook есть два пикселя на точку - соотношение 2), то вам необходимо умножить wи hна это соотношение.
BallpointBen

в новой версии можно было использовать element.screenshot ('elemenent.png'), см. ответ @ rovr138
tinyhare

@tinyhare Это было доступно только в Firefox, когда был создан ответ. Думаю, теперь он доступен и в хроме. Обновление ответа.
codelord

1
@puppet Для загрузки в память сделайте это. from StringIO import StringIO; from PIL import Image; img = Image.open(StringIO(image))
codelord

1
У меня была аналогичная проблема с @puppet. Вот что сработало для меня: import io; from PIL import Image; img = Image.open(io.BytesIO(image)); img.save("image.png")
Somto Muotoe

9

В Node.jsя написал следующий код, который работает, но основан не на официальном WebDriverJS Selenium , а на 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;
        });
};

Ваша библиотека EasyImage не работает: «ImageMagickMissingError»
Низар Б.

9

Фреймворк 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"));

Дополнительные сведения и примеры кода см. В этой статье .


Будьте осторожны , вы можете также необходимы .shootingStrategy(ShootingStrategies.viewportPasting(100))также с SPECIFIC WEB ELEMENTрежимом, или он не может охватить весь элемент.
user1686407

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

Спасибо. Это было очень полезно, по существу и идеально.
Sorrel Vesper

5

Я потратил много времени на создание скриншотов, и хочу сохранить ваш. Я использовал хром + селен + С #, результат был ужасным. Наконец, я написал функцию:

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

1
Он отлично работает, пока вы пытаетесь захватить видимый элемент без прокрутки. Когда вам нужно прокрутить до элемента, чтобы захватить его, тогда смещение по оси y вычисляется от верхней части страницы, которая затем выходит за границы полноэкранного изображения. Итак, самое простое решение - либо увеличить размер экрана, используя код this.driver.manage (). Window (). SetSize (new Dimension (1680, 1050)); или удалить ненужные элементы через css. Правильным решением было бы вычислить смещение по оси Y от прокрутки.
Ichwardort

4

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

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, сколько душе угодно.


3

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

Не нужно получать полное изображение и получать часть полноэкранного изображения.

Это могло быть недоступно, когда был создан ответ Рохита .


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

2

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

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

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


Пожалуйста, вставьте код в свой ответ вместо ссылки на другой источник
supersan

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

1

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


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

См. Эту ссылку для получения дополнительной информации: [Automation Hub Point] ( automationhubpoint.blogspot.in/2017/01/… )
ER.swatantra 02

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

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

0

Если вы получаете исключение java.awt.image.RasterFormatException в chrome или хотите прокрутить элемент в поле зрения, сделайте снимок экрана.

Вот решение из ответа @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);

Я использую selenium-java-2.53.1, группу компиляции: 'org.seleniumhq.selenium', имя: 'selenium-java', версия: '2.53.1', chrome-web-driver, я пытаюсь обрезать По .xpath (".// img [@class = 'captcha']") с веб-страницы resident.uidai.gov.in/offlineaadhaar , но ваш код работает неправильно. Это обрезка неправильной части страницы. не могли бы вы помочь мне обрезать капчу.
vijay

0

Это моя версия на C #, я в основном получил большую часть ответа Брука и изменил его в соответствии со своей целью

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[]));
        }
    }

0

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

Примечание: мы приводим WebElementк TakesScreenshotэкземпляру, поэтому мы специально фиксируем только этот элемент в изображении. Если вам нужна полная страница / окно, вы должны driverвместо этого выполнить трансляцию .

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

-1

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

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

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

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


-2

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


Я получаю эту ошибку, когда пробую ваш метод: Невозможно применить прозрачный прокси к типу OpenQA.Selenium.Remote.RemoteWebElement
shanabus

Я использую это исключительно с драйвером Chrome, какой драйвер вы используете?
thepirat000

Я также использую ChromeDriver. В моих тестах используется IWebElements, и мы следуем методу PageFactory из пакета Nuget OpenQA.Selenium.Support.
шанабус
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.