如何在python中使用Selenium WebDriver截取部分屏幕截图?


75

我为此进行了很多搜索,但找不到解决方案。这是java中可能的解决方案的类似问题

Python中有类似的解决方案吗?

Answers:


138

除了硒以外,此示例还需要PIL映像库。有时将其作为标准库之一放入,有时却不作为,但如果没有,则可以使用pip install Pillow

from selenium import webdriver
from PIL import Image
from io import BytesIO

fox = webdriver.Firefox()
fox.get('http://stackoverflow.com/')

# now that we have the preliminary stuff out of the way time to get that image :D
element = fox.find_element_by_id('hlogo') # find part of the page you want image of
location = element.location
size = element.size
png = fox.get_screenshot_as_png() # saves screenshot of entire page
fox.quit()

im = Image.open(BytesIO(png)) # uses PIL library to open image in memory

left = location['x']
top = location['y']
right = location['x'] + size['width']
bottom = location['y'] + size['height']


im = im.crop((left, top, right, bottom)) # defines crop points
im.save('screenshot.png') # saves new cropped image

最后输出是... Stackoverflow徽标!!!

在此处输入图片说明

当然,现在仅获取静态图像将是过大的选择,但是如果您想要获取需要Javascript才能实现的功能,那可能是一个可行的解决方案。


18
您也可以直接在内存中获取屏幕截图:img = Image.open(StringIO(base64.decodestring(driver.get_screenshot_as_base64())))
ejk314 2013年

7
内存加载的另一种方法是img = fox.get_screenshot_as_png()然后img = Image.open(StringIO(img))将其加载为PIL映像。
Yellowcap 2014年

6
注释来自@ sukrit-gupta的NAA:RandomPhobia,对于不需要滚动的静态页面,您的回答非常有用。万一某人需要从需要滚动的大页面获取图像,则应使用location_once_scrolled_into_view函数。因此,将location = element.location替换为:location = img.location_once_scrolled_into_view另外,请确保您使用Chrome而不是Firefox,因为Chrome仅截取可见区域的屏幕快照,而Firefox截取完整选项卡的屏幕快照。
bummi 2015年

6
@yellowcap提出的建议的后续行动:请注意,在Python 3+中,您应该BytesIO而不是StringIO
Alex P. Miller

4
图像被放大时,我面临调整大小的问题。屏幕截图有效,但是裁剪图像似乎无效。有人面对过同样的事情吗?
Sumit Murari

31

在python3.5中为我工作

from selenium import webdriver


fox = webdriver.Firefox()
fox.get('http://stackoverflow.com/')
image = fox.find_element_by_id('hlogo').screenshot_as_png

ps

保存到文件

image=driver.find_element_by_id('hlogo').screenshot(output_file_path)

1
@Julius不,不应该-仅当部分屏幕截图与分配了ID的元素完全匹配时才足够。
减少活动

@Julius仍然不确定它在哪里以及如何工作。在带有Chrome的Python 2.7中,它不起作用。
用户

我使用selenium2在chrome / python 2.7上工作。 image = driver.find_element_by_id('el_id').screenshot_as_png这是元素的属性吗,如何将其另存为图像?
tanvi

我们如何继续保存图像?
Lakshmi Narayanan

2
@tanvi @Lakshmi你们可以做到image = driver.find_element_by_id('el_id').screenshot(output_file_path)。请参阅此处获取API文档。
肯公园

7

我写了这个有用的python3函数。

from base64 import b64decode
from wand.image import Image
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.action_chains import ActionChains
import math

def get_element_screenshot(element: WebElement) -> bytes:
    driver = element._parent
    ActionChains(driver).move_to_element(element).perform()  # focus
    src_base64 = driver.get_screenshot_as_base64()
    scr_png = b64decode(src_base64)
    scr_img = Image(blob=scr_png)

    x = element.location["x"]
    y = element.location["y"]
    w = element.size["width"]
    h = element.size["height"]
    scr_img.crop(
        left=math.floor(x),
        top=math.floor(y),
        width=math.ceil(w),
        height=math.ceil(h),
    )
    return scr_img.make_blob()

它以字节为单位返回显示元素的png图像。限制:元素必须适合视口。
您必须安装棒模块才能使用它。


1
好的代码!当我尝试使用chrome中的长页面时,我认为x = element.location_once_scrolled_into_view["x"] y = element.location_once_scrolled_into_view["y"]因为location返回的可能比窗口大。
Vimos

6

这是一个执行此功能的函数,在将大小传递给crop函数之前,必须将其大小转换为整数:

from PIL import Image
from StringIO import StringIO
def capture_element(element,driver):
  location = element.location
  size = element.size
  img = driver.get_screenshot_as_png()
  img = Image.open(StringIO(img))
  left = location['x']
  top = location['y']
  right = location['x'] + size['width']
  bottom = location['y'] + size['height']
  img = img.crop((int(left), int(top), int(right), int(bottom)))
  img.save('screenshot.png')

这与已接受的答案几乎相同,但又增加了一个错误,即OP不希望使用硒。
细设

它确实使用硒,但是这里不需要import语句,它还包括将位置从float转换为int的功能,如果位置不是整数,则img.crop函数会引发异常
SEDaradji

TypeError: initial_value must be str or None, not bytes
pyd

您的输出是什么(img),是方法还是字节对象?
pyd

我不确定我是否理解您的问题
SEDaradji,

5

为响应RandomPhobia的一个很好的回答,扩展注释,以下是两个具有正确导入语句的解决方案,它们将打开全屏屏幕截图,而无需先保存到文件中:

from selenium import webdriver
from PIL import Image
from StringIO import StringIO
import base64

DRIVER = 'chromedriver'
browser = webdriver.Chrome(DRIVER)

browser.get( "http:\\\\www.bbc.co.uk" )

img 1 = Image.open(StringIO(base64.decodestring(browser.get_screenshot_as_base64())))

img 2 = Image.open(StringIO(browser.get_screenshot_as_png()))

并且因为我确定您的下一个问题是:“很好,但是哪个最快?”,这是确定方法的方法(我发现第一种方法在一定距离内最快):

import timeit

setup = '''
from selenium import webdriver
from PIL import Image
from StringIO import StringIO
import base64

DRIVER = 'chromedriver'
browser = webdriver.Chrome(DRIVER)
browser.get( "http:\\\\www.bbc.co.uk" )

file_name = 'tmp.png'
'''

print timeit.Timer('Image.open(StringIO(browser.get_screenshot_as_png()))', setup=setup).repeat(2, 10)
print timeit.Timer('Image.open(StringIO(base64.decodestring(browser.get_screenshot_as_base64())))', setup=setup).repeat(2, 10)
print timeit.Timer('browser.get_screenshot_as_file(file_name); pil_img = Image.open(file_name)', setup=setup).repeat(2, 10)

5

按元素截图:

from PIL import Image
from io import BytesIO


image = self.browser.driver.find_element_by_class_name('example.bla.bla').screenshot_as_png
im = Image.open(BytesIO(image))  # uses PIL library to open image in memory
im.save('example.png')

我也这样做,但是遇到以下错误: WebDriverException: Message: unknown error: failed to parse value of getElementRegion (Session info: chrome=78.0.3904.108)
Mostafa Ghadimi


0

我将@randomphobia的答案转换为一个函数。我也使用了@bummis的使用location_once_scrolled_into_view而不是的建议,location以便对页面的大小都一概而论。

from selenium import webdriver
from PIL import Image
from io import BytesIO

def take_screenshot(element, driver, filename='screenshot.png'):
  location = element.location_once_scrolled_into_view
  size = element.size
  png = driver.get_screenshot_as_png() # saves screenshot of entire page

  im = Image.open(BytesIO(png)) # uses PIL library to open image in memory

  left = location['x']
  top = location['y']
  right = location['x'] + size['width']
  bottom = location['y'] + size['height']


  im = im.crop((left, top, right, bottom)) # defines crop points
  im.save(filename) # saves new cropped image

这是要点:https : //gist.github.com/WittmannF/b714d3ceb7b6a5cd50002f11fb5a4929

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.