如何使用Selenium WebDriver进行局部截图(框架)?

21

使用WebDriver,是否可以仅对frameset中的一个frame(而不是整个窗口)进行屏幕截图?

或者,是否可以定义窗口的坐标来进行屏幕截图,或在之后裁剪图像?

5个回答

26

这应该可以运行:

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

public class Shooter{

    private WebDriver driver;

    public void shootWebElement(WebElement element) throws IOException  {

        File screen = ((TakesScreenshot) this.driver).getScreenshotAs(OutputType.FILE);

        Point p = element.getLocation();

        int width = element.getSize().getWidth();
        int height = element.getSize().getHeight();

        BufferedImage img = ImageIO.read(screen);

        BufferedImage dest = img.getSubimage(p.getX(), p.getY(), width,   
                                 height);

        ImageIO.write(dest, "png", screen);

        File f = new File("S:\\ome\\where\\over\\the\\rainbow");

        FileUtils.copyFile(screen, f);

    }
}

太好了!这正是我在寻找的。高度变量处的“-”符号错误导致了一次RasterFormatException异常。非常感谢。 - timomeinen
运行良好。但是p.moveBy有什么作用?我不能看出使用它和删除该行的区别。 - timomeinen
你们会写Ruby吗?请给些建议。 - Amey

8

Python解决方案(依赖项:PIL或Pillow):

from PIL import Image
from selenium import webdriver

def element_screenshot(driver, element, filename):
    bounding_box = (
        element.location['x'], # left
        element.location['y'], # upper
        (element.location['x'] + element.size['width']), # right
        (element.location['y'] + element.size['height']) # bottom
    )
    return bounding_box_screenshot(driver, bounding_box, filename)

def bounding_box_screenshot(driver, bounding_box, filename):
    driver.save_screenshot(filename)
    base_image = Image.open(filename)
    cropped_image = base_image.crop(bounding_box)
    base_image = base_image.resize(cropped_image.size)
    base_image.paste(cropped_image, (0, 0))
    base_image.save(filename)
    return base_image

if __name__ == '__main__':
    driver = webdriver.Firefox()
    driver.get('https://www.google.com/?gws_rd=ssl')
    element = driver.find_element_by_id('body')

    screenshot = element_screenshot(driver, element, 'element.png') # Screenshot the '#body' element

    bounding_box = (100, 100, 600, 600)
    screenshot = bounding_box_screenshot(driver, bounding_box, 'box.png') # Screenshot the bounding box (100, 100, 600, 600)

6

Ruby解决方案

准备工作

安装xvfb

apt-get install xvfb -y

安装无头浏览器和图像处理宝石包。
gem install chunky_png
gem install headless
gem install selenium-webdriver

安装谷歌浏览器驱动
wget http://chromedriver.googlecode.com/files/chromedriver_linux64_<latest>.zip
apt-get install unzip
unzip chromedriver_linux64_<latest>.zip
cp chromedriver /usr/local/bin

更多信息可以在这里找到

代码

#!/usr/bin/env ruby

require "headless"
require "selenium-webdriver"
require 'chunky_png'

headless = Headless.new
headless.start

site = "?_some_site_?"

driver = Selenium::WebDriver.for :chrome
driver.navigate.to site
sleep 1
driver.save_screenshot('screenshot.png')

el= driver.find_element(:xpath, '?_some_xpath_?')

image = ChunkyPNG::Image.from_file('screenshot.png')

image.crop!(el.location.x + 1, el.location.y + 1, el.size.width, el.size.height)
image.save('croped.png')

driver.quit
headless.destroy

2

我将为您提供基于C#的解决方案,用于在Selenium中获取特定Html元素的屏幕截图:

首先,我们需要使用selenium web driver的GetScreenShot方法获取整个网页的屏幕截图,如下所示。

Screenshot screenshot = ((ITakesScreenshot)this.driver).GetScreenshot(); 
screenshot.SaveAsFile(filename, System.Drawing.Imaging.ImageFormat.Jpeg);

然后,通过使用 Selenium 的 FindElement() 方法提供 id 或 class 名称,从指定的 HTML 元素位置、高度和宽度创建一个矩形。

Image img = Bitmap.FromFile(uniqueName);
Rectangle rect = new Rectangle();

if (element != null)
{
    // Get the Width and Height of the WebElement using
    int width = element.Size.Width;
    int height = element.Size.Height;

    // Get the Location of WebElement in a Point.
    // This will provide X & Y co-ordinates of the WebElement
    Point p = element.Location;

    // Create a rectangle using Width, Height and element location
    rect = new Rectangle(p.X, p.Y, width, height);
}

使用它,我们将像下面这样裁剪屏幕截图,结果将是特定于屏幕截图的Web元素。
Bitmap bmpImage = new Bitmap(img);
var cropedImag = bmpImage.Clone(rect, bmpImage.PixelFormat);

以下是完整的代码方法:

/// <summary>
/// Captures the element screen shot.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="uniqueName">Name of the unique.</param>
/// <returns>returns the screenshot  image </returns>
public Image CaptureElementScreenShot(HTMLElement element, string uniqueName)
{
    Screenshot screenshot = ((ITakesScreenshot)this.driver).GetScreenshot();
    screenshot.SaveAsFile(filename, System.Drawing.Imaging.ImageFormat.Jpeg);

    Image img = Bitmap.FromFile(uniqueName);
    Rectangle rect = new Rectangle();

    if (element != null)
    {
        // Get the Width and Height of the WebElement using
        int width = element.Size.Width;
        int height = element.Size.Height;

        // Get the Location of WebElement in a Point.
        // This will provide X & Y co-ordinates of the WebElement
        Point p = element.Location;

        // Create a rectangle using Width, Height and element location
        rect = new Rectangle(p.X, p.Y, width, height);
    }

    // croping the image based on rect.
    Bitmap bmpImage = new Bitmap(img);
    var cropedImag = bmpImage.Clone(rect, bmpImage.PixelFormat);

    return cropedImag;
}

1
Scala解决方案:
import javax.imageio.ImageIO
import java.awt.image.BufferedImage

// phone is a case class with witdth and height Int fields

def producer {       
 [..]
 processScreenshot(driver.getScreenshotAs(OutputType.FILE), ph)
}

def processScreenshot(file: File, phone: Phone) = {
 val img: BufferedImage = ImageIO.read(file)
 val w = math.min(img.getWidth, phone.width)
 val h = math.min(img.getHeight, phone.height)
 val dest = img.getSubimage(0, 0, w, h)
 ImageIO.write(dest, "png", new File(s"/tmp/${un}_${phone.file}.png"))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接