¿Cómo capturar la captura de pantalla de un elemento específico en lugar de la página completa usando Selenium Webdriver?

82

Actualmente estoy tratando de capturar una captura de pantalla usando Selenium WebDriver. Pero solo puedo obtener la captura de pantalla de la página completa. Sin embargo, lo que quería es capturar solo una parte de la página o quizás solo un elemento específico basado en la identificación o cualquier localizador de elemento específico. (Por ejemplo, deseo capturar la imagen con id de imagen = "Mariposa")

¿Hay alguna forma de capturar una captura de pantalla por elemento o elemento seleccionado?

fj123
fuente
1
AFAIK, la facilidad es solo para capturar la página completa. No tenemos una función de captura de pantalla que tome la identificación del elemento o el nombre como entrada.
Hemanth
Cualquiera podría decirme cuál es la llamada al método para BUfferedImage en c #? No pude encontrar ningún método similar relacionado con esto.
fj123

Respuestas:

117

Podemos obtener la captura de pantalla del elemento recortando la captura de pantalla completa de la página como se muestra a continuación:

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);
Surya
fuente
Gracias por tu respuesta. Sin embargo, ¿por qué mi controlador web es diferente al tuyo? usa IWebDriver, ITakeScreenshot y no hay OutputType.FILE ni BufferedImage ... ¿estoy usando la versión desactualizada de selenium webdriver?
fj123
¿Está utilizando el enlace de controlador web C #?
Surya
Sí, eso creo. Anteriormente estaba usando RC y recientemente cambié para usar el controlador web.
fj123
Esta implementación es para el enlace de Java. Este concepto también debería funcionar para C #. Pero no estoy muy al tanto del lenguaje C #. Necesita usar bibliotecas equivalentes de C # (BufferedImage, ImageIO ...)
Surya
4
El código anterior no funciona en Chrome. Una excepción java.awt.image.RasterFormatException: (y + height) está fuera de Raster fue lanzada en la línea BufferedImage eleScreenshot = fullImg.getSubimage (point.getX (), point.getY (), eleWidth, eleHeight);
Ripon Al Wasim
13

Aquí hay una versión de Python 3 que usa Selenium webdriver y Pillow. Este programa captura la captura de pantalla de toda la página y recorta el elemento según su ubicación. La imagen del elemento estará disponible como image.png. Firefox admite guardar la imagen del elemento directamente usando 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')

Actualizar

Ahora Chrome también admite capturas de pantalla de elementos individuales. Por lo tanto, puede capturar directamente la captura de pantalla del elemento web como se indica a continuación.

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")
codigo
fuente
4
Estoy bastante seguro de que element.sizese da en puntos, mientras que la captura de pantalla producida por driver.save_screenshottiene dimensiones de píxeles. Si su pantalla tiene una proporción de píxel a punto distinta de 1 (por ejemplo, los MacBooks con retina tienen dos píxeles por punto, una proporción de 2), entonces debe multiplicar wy hpor esa proporción.
BallpointBen
la nueva versión ha podido usar element.screenshot ('elemenent.png'), vea la respuesta de @ rovr138
tinyhare
@tinyhare Solo estaba disponible en Firefox cuando se creó la respuesta. Creo que ahora también está disponible en cromo. Actualizando la respuesta.
codelord
1
@puppet Para cargar en la memoria haga esto. from StringIO import StringIO; from PIL import Image; img = Image.open(StringIO(image))
codelord
1
Tuve un problema similar al de @puppet. Esto es lo que funcionó para mí: import io; from PIL import Image; img = Image.open(io.BytesIO(image)); img.save("image.png")
Somto Muotoe
9

En Node.js, escribí el siguiente código que funciona pero no se basa en el WebDriverJS oficial de selenium, sino en SauceLabs's WebDriver: WD.js y una biblioteca de imágenes muy compacta llamada EasyImage .

Solo quiero enfatizar que realmente no puede tomar la captura de pantalla de un elemento, pero lo que debe hacer es primero, tomar la captura de pantalla de toda la página, luego seleccionar la parte de la página que le gusta y recortar esa parte específica:

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

Y la función cropInFileFunction, es así:

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;
        });
};
ambodi
fuente
Su biblioteca EasyImage no funciona: "ImageMagickMissingError"
Nizar B.
9

El marco ASHOT de Yandex se puede utilizar para tomar capturas de pantalla en los scripts de Selenium WebDriver para

  • páginas web completas
  • elementos web

Este marco se puede encontrar en https://github.com/yandex-qatools/ashot .

El código para tomar las capturas de pantalla es muy sencillo:

PÁGINA COMPLETA

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

ELEMENTO WEB ESPECÍFICO

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

Vea más detalles y más ejemplos de código en este artículo .

Alex Siminiuc
fuente
Tenga cuidado, es posible que también lo necesite .shootingStrategy(ShootingStrategies.viewportPasting(100))con el SPECIFIC WEB ELEMENTmodo, o puede que no capture todos los elementos.
user1686407
8

Para todos los que soliciten código en C #, a continuación se muestra una versión simplificada de mi implementación.

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);
    }
}
Arroyo
fuente
Gracias. Eso fue muy útil y fue al grano y perfecto.
Sorrel Vesper
5

Perdí mucho tiempo tomando capturas de pantalla y quiero guardar la tuya. He usado chrome + selenium + c # el resultado fue totalmente horrible. Finalmente escribí una función:

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); 
Rajendra_Prasad
fuente
1
Funciona perfectamente bien siempre que intente capturar un elemento que sea visible sin desplazarse. Cuando necesita desplazarse a un elemento para capturarlo, el desplazamiento y se calcula desde la parte superior de la página, que luego excede los límites de la imagen de pantalla completa. Así que la solución más sencilla es aumentar el tamaño de la pantalla code this.driver.manage (). Window (). SetSize (new Dimension (1680, 1050)); o para eliminar cualquier elemento no necesario a través de css. La solución adecuada sería calcular el desplazamiento y a partir del desplazamiento.
Ichwardort
3

La respuesta de Surya funciona muy bien si no le importa involucrar el disco IO. Si prefiere no hacerlo, este método puede ser mejor para usted.

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

Si lo prefiere, puede omitir declarar screengraby en su lugar hacer

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

que es más limpio, pero lo dejé para mayor claridad. Luego puede guardarlo como un archivo o ponerlo en un JPanel al contenido de su corazón.

rath
fuente
3

Python 3

Probado con Selenium 3.141.0 y chromedriver 73.0.3683.68, esto funciona,

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

No es necesario obtener una imagen completa y obtener una sección de una imagen a pantalla completa.

Es posible que esto no estuviera disponible cuando se creó la respuesta de Rohit .

rovr138
fuente
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();
        }
    }
Waqar Ullah Khan
fuente
2

Si está buscando una solución de JavaScript, aquí está mi esencia:

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

La idea básica es la misma, primero tome la captura de pantalla y luego recórtela. Sin embargo, mi solución no requerirá otras bibliotecas, solo código API de WebDriver puro. Sin embargo, el efecto secundario es que puede aumentar la carga de su navegador de prueba.

sillicón
fuente
Pegue el código en su respuesta en lugar de vincularlo a otra fuente
supersan
2

Aquí hay una función de extensión para 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();
    }
}

Ahora puedes usarlo para tomar la imagen de cualquier elemento como este:

var image = webDriver.GetElementImage(By.Id("someId"));
Hüseyin Yağlı
fuente
1

Considere el uso de aguja: herramienta para comparación visual automatizada https://github.com/bfirsh/needle , que tiene una funcionalidad incorporada que permite tomar capturas de pantalla de elementos específicos (seleccionados por el selector de CSS). La herramienta funciona en WebDriver de Selenium y está escrita en Python.

Jan Rozycki
fuente
1

Debajo de la función para tomar una instantánea de un elemento específico en Selenium. Aquí el controlador es un tipo de 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);
 }
ER.swatantra
fuente
Consulte este enlace para obtener más información: [Automation Hub Point] ( automationhubpoint.blogspot.in/2017/01/… )
ER.swatantra
1

código 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;
}
Andrés
fuente
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);                        
            }
        }
    }
}
Mnemo
fuente
0

Si obtiene una excepción java.awt.image.RasterFormatException en Chrome, o si desea desplazar un elemento a la vista, haga una captura de pantalla.

Aquí hay una solución de la respuesta de @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);
Lei verde
fuente
Estoy usando selenium-java-2.53.1, grupo de compilación: 'org.seleniumhq.selenium', nombre: 'selenium-java', versión: '2.53.1', chrome-web-driver, estoy tratando de recortar por .xpath (".// img [@class = 'captcha']") de la página web resident.uidai.gov.in/offlineaadhaar , pero su código no funciona correctamente. Está recortando una parte incorrecta de la página. ¿Podrías ayudarme a recortar el captcha?
vijay
0

Esta es mi versión, en C #, básicamente obtuve la mayor parte de la respuesta de Brook y la modifiqué para que se ajustara a mi propósito

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[]));
        }
    }
Hoang Minh
fuente
-1

Creo que esto no funcionará para usted ya que usa C # y mi solución incluye una biblioteca Java, sin embargo, tal vez otros lo encuentren útil.

Para realizar capturas de pantalla personalizadas, puede utilizar la biblioteca Shutterbug. La convocatoria específica para este fin sería:

Shutterbug.shootElement(driver, element).save();
Marlies
fuente
-1

Seguí el código de muestra de @codeslord, pero por alguna razón tuve que acceder a mis datos de captura de pantalla de manera diferente:

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

(usando Python 3.7, Selenium 3.141.0 y Mozilla Geckodriver 71.0.0.7222)

Rishi Latchmepersad
fuente
-2

Estoy usando una versión modificada de la respuesta de @ Brook y funciona bien incluso para elementos que necesitan que la página se desplace.

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

Los dos iferan necesarios (al menos para el controlador de Chrome) porque el tamaño del recorte excedía en 1 píxel el tamaño de la captura de pantalla, cuando era necesario desplazarse.

thepirat000
fuente
Recibo este error cuando intento su método: No se puede enviar un proxy transparente para escribir 'OpenQA.Selenium.Remote.RemoteWebElement'
shanabus
Lo uso exclusivamente con el controlador de Chrome, ¿qué controlador usas?
thepirat000
También estoy usando ChromeDriver. Mis pruebas usan IWebElements y estamos siguiendo el método PageFactory del paquete nuget OpenQA.Selenium.Support.
shanabus