Como capturar a captura de canvas de um elemento específico em vez de uma página inteira usando o Selenium Webdriver?

Atualmente estou tentando capturar uma captura de canvas usando o Selenium WebDriver. Mas só posso obter a captura de canvas inteira. No entanto, o que eu queria era apenas capturar uma parte da página ou talvez apenas um elemento específico baseado em ID ou em qualquer localizador de elemento específico. (Por exemplo, desejo capturar a imagem com a imagem id = “Butterfly”)

Existe alguma maneira de capturar uma captura de canvas por item ou elemento selecionado?

Podemos obter a captura de canvas do elemento cortando a captura de canvas da página inteira conforme abaixo:

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

No Node.js , eu escrevi o seguinte código que funciona, mas não é baseado no WebDriverJS oficial do selenium, mas baseado no SauceLabs's WebDriver SauceLabs : o WD.js e uma biblioteca de imagens muito compacta chamada EasyImage .

Eu só quero enfatizar que você não pode realmente tirar a foto de um elemento, mas o que você deve fazer é primeiro, tirar o screenshot de toda a página, em seguida, selecione a parte da página que você gosta e cortar essa 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(); }); }); }); }); 

E o cropInFileFunction, é assim:

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

O framework ASHOT do Yandex pode ser usado para tirar screenshots nos scripts do Selenium WebDriver para

  • páginas da web completas
  • elementos da web

Este framework pode ser encontrado em https://github.com/yandex-qatools/ashot .

O código para tirar as capturas de canvas é muito simples:

PÁGINA INTEIRA

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

Veja mais detalhes e mais exemplos de código neste artigo .

Eu perdi muito tempo em tirar screenshots e quero salvar a sua. Eu usei cromo + selenium + c # o resultado foi totalmente horrível. Finalmente eu escrevi uma function:

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

Para todos que pedem código em C #, abaixo está uma versão simplificada da minha implementação.

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

A resposta da Surya funciona muito bem se você não se importar com o IO do disco. Se você preferir não, então esse método pode ser melhor para você

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

Se você preferir, você pode pular declarando screengrab e fazendo

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

que é mais limpo, mas deixei para clarificar. Você pode salvá-lo como um arquivo ou colocá-lo em um JPanel para o conteúdo do seu coração.

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

Considere o uso de ferramenta de agulha para comparação visual automatizada https://github.com/bfirsh/needle , que tem uma funcionalidade incorporada que permite tirar screenshots de elementos específicos (selecionados pelo seletor CSS). A ferramenta funciona no WebDriver do Selenium e é escrita em Python.

Abaixo a function para tirar instantâneo de um elemento específico no Selenium. Aqui o driver é um 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); } 

Se você está procurando uma solução JavaScript, aqui está minha essência:

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

A idéia básica é a mesma, tire a primeira canvas e depois corte-a. No entanto, minha solução não exigirá outras bibliotecas, apenas código de API do WebDriver puro. No entanto, o efeito colateral é que isso pode aumentar a carga do seu navegador de teste.

Aqui está uma function de extensão 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(); } } 

Agora você pode usá-lo para tirar a imagem de qualquer elemento como este:

 var image = webDriver.GetElementImage(By.Id("someId")); 

Aqui está uma versão do Python 3 usando o Selenium webdriver e o Pillow. Este programa captura a captura de canvas de toda a página e corta o elemento com base em sua localização. A imagem do elemento estará disponível como image.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') 
 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); } } } } 

Eu acredito que isso não vai funcionar para você enquanto você usa C # e minha solução inclui uma biblioteca Java, no entanto, talvez outros acharão útil.

Para capturar capturas de canvas personalizadas, você pode usar a biblioteca Shutterbug. O convite específico para este fim seria:

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

Estou usando uma versão modificada da resposta do @ Brook e está funcionando bem, mesmo para elementos que precisam da página a ser rolada.

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

Os dois if s eram necessários (pelo menos para o driver do Chrome), porque o tamanho do crop excedia em 1 pixel o tamanho da imagem, quando era necessária a rolagem.