如何使用Selenium Webdriver捕获特定元素的屏幕截图而不是整个页面?
目前我正在尝试使用Selenium WebDriver捕捉屏幕截图。 但我只能获得整个页面的屏幕截图。 但是,我想要的只是捕获页面的一部分,或者也许只是基于ID或任何特定的元素定位器的特定元素。 (例如,我希望捕捉图片id =“蝴蝶”)
有没有办法通过选定的项目或元素捕捉屏幕截图?
我们可以通过裁剪整个页面截图来获取元素截图,如下所示:
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
,我写了下面的代码,但它不是基于SauceLabs's WebDriver
官方WebDriverJS,而是基于SauceLabs's WebDriver
: WD.js和一个名为EasyImage的非常紧凑的图像库。
我只是想强调,你不能真正采取元素的屏幕截图,但你应该做的是首先,把整个页面的截图,然后select你喜欢的页面的一部分,并裁剪该特定的部分:
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; }); };
Yandex的ASHOT框架可用于在Selenium WebDriver脚本中获取屏幕截图
- 完整的网页
- web元素
这个框架可以在https://github.com/yandex-qatools/ashotfind。;
截图的代码非常简单:
整个页面
screenshot = new AShot().shootingStrategy( new ViewportPastingStrategy(1000)).takeScreenshot(driver); ImageIO.write(screenshot.getImage(), "PNG", new File("c:\\temp\\results.png"));
特定的WEB元素
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"));
查看本文的更多详细信息和更多代码示例。
我花了很多时间来截图,我想保存你的。 我用铬+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); } }
如果你不介意涉及磁盘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中,以放入您的内容。
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(); } }
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); } } } }
考虑使用针工具进行自动化视觉比较https://github.com/bfirsh/needle ,它具有内置的function,允许截取特定元素(由CSSselect器select)。 该工具在Selenium的WebDriver上工作,并用Python编写。
Selenium中的特定元素的快照function下面。 这里的驱动程序是一种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解决scheme,这是我的要点:
https://gist.github.com/sillicon/4abcd9079a7d29cbb53ebee547b55fba
基本的想法是一样的,先把屏幕截图,然后裁剪。 但是,我的解决scheme不需要其他库,只需要纯WebDriver API代码。 但是,副作用是可能会增加testing浏览器的负载。
这里是C#的扩展函数:
public static Bitmap GetElementImage(this IWebDriver webDriver, IWebElement element) { var screenShot = (webDriver as ITakesScreenshot).GetScreenshot(); using (var ms = new MemoryStream(screenShot.AsByteArray)) { var screenBitmap = new Bitmap(ms); return screenBitmap.Clone( new Rectangle( element.Location.X, element.Location.Y, element.Size.Width, element.Size.Height ), screenBitmap.PixelFormat ); } }
现在你可以使用它来像这样的任何元素的形象:
IWebElement temp = Driver.FindElement(By.Id("someId")); var image = webDriver.GetElementImage(temp);
我相信在你使用C#时,这不会起作用,而且我的解决scheme包含一个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); } } }
这两个if
是必要的(至less对于铬驱动程序),因为作物的大小超过了1像素的截图大小,当需要滚动。