如何使用Selenium Webdriver捕获特定元素而不是整个页面的屏幕截图?

fj1*_*123 71 selenium screenshot selenium-webdriver

目前我正在尝试使用Selenium WebDriver捕获屏幕截图.但我只能获得整页屏幕截图.但是,我想要的只是捕获页面的一部分,或者只是基于ID或任何特定元素定位器捕获特定元素.(例如,我希望用图像id ="Butterfly"捕获图片)

有没有办法按选定的项目或元素捕获屏幕截图?

Sur*_*rya 102

我们可以通过裁剪整个页面截图来获取元素截图,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)

  • 上述代码无法在Chrome中使用.异常java.awt.image.RasterFormatException:(y + height)在Raster之外被抛出BufferedImage行eleScreenshot = fullImg.getSubimage(point.getX(),point.getY(),eleWidth,eleHeight); (4认同)

amb*_*odi 10

Node.js,我编写了以下代码,但它不是基于selenium的官方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();
                        });
                    });
                });
            }); 
Run Code Online (Sandbox Code Playgroud)

而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;
        });
};
Run Code Online (Sandbox Code Playgroud)


cod*_*ord 9

这是使用Selenium Webdriver和Pillow的Python 3版本。该程序捕获整个页面的屏幕快照,并根据其位置裁剪元素。元素图像将以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')
Run Code Online (Sandbox Code Playgroud)

更新资料

现在,chrome还支持单个元素的屏幕截图。因此,您可以直接捕获Web元素的屏幕截图,如下所示。

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")
Run Code Online (Sandbox Code Playgroud)

  • 我和@puppet 有类似的问题。这对我有用:`import io; 从 PIL 导入图像;img = Image.open(io.BytesIO(image)); img.save("image.png")` (3认同)
  • 我很确定`element.size`是用磅表示的,而`driver.save_screenshot`产生的屏幕截图的像素大小。如果您的屏幕的像素点比不是1(例如,视网膜MacBooks每点有两个像素-比率为2),则需要将“ w”和“ h”乘以该比率。 (2认同)

小智 8

Yandex的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"));
Run Code Online (Sandbox Code Playgroud)

特定的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"));
Run Code Online (Sandbox Code Playgroud)

查看更多的细节和更多的代码样本这篇文章.


Bro*_*ook 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);
    }
}
Run Code Online (Sandbox Code Playgroud)


rov*_*138 6

蟒蛇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')
Run Code Online (Sandbox Code Playgroud)

无需获取完整图像并获取全屏图像的一部分。

创建罗希特的答案时,这可能不可用。


小智 5

我在截图上浪费了很多时间,我想保存你的截图。我用了铬+硒+ 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); 
Run Code Online (Sandbox Code Playgroud)


rat*_*ath 5

如果您不介意涉及磁盘 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());
}
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以跳过声明screengrab并执行

img = ImageIO.read(
    new ByteArrayInputStream(
        ((TakesScreenshot) d).getScreenshotAs(OutputType.BYTES)));
Run Code Online (Sandbox Code Playgroud)

这更干净,但为了清楚起见我将其保留下来。然后您可以将其另存为文件将其放入 JPanel 中,随心所欲。


Lor*_*nzo 5

我认为这里的大多数答案都是过度设计的。我这样做的方法是通过 2 个辅助方法,第一个方法等待基于任何选择器的元素;第二个是截取屏幕截图。

注意:我们将 投射WebElement到一个TakesScreenshot实例,因此我们只专门捕获图像中的该元素。如果您想要完整的页面/窗口,则应该进行强制driver转换。

编辑:我忘了说我正在使用 Java 和 Selenium v​​3(但 v4 应该相同)

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));
}
Run Code Online (Sandbox Code Playgroud)

然后只需截图你想要的任何东西,如下所示:

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);
Run Code Online (Sandbox Code Playgroud)