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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15018372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:07:20  来源:igfitidea点击:

How to take partial screenshot with Selenium WebDriver in python?

pythonselenium

提问by streamoverflowed

I have searched a lot for this but couldn't find a solution. Here's a similar questionwith a possible solution in java.

我为此搜索了很多,但找不到解决方案。这是一个类似的问题,在 Java 中有一个可能的解决方案。

Is there a similar solution in Python?

Python中是否有类似的解决方案?

采纳答案by RandomPhobia

Other than Selenium, this example also requires the PIL Imaging library. Sometimes this is put in as one of the standard libraries and sometimes it's not, but if you don't have it you can install it with pip install Pillow

除了 Selenium,这个例子还需要 PIL Imaging 库。有时这是作为标准库之一放入的,有时不是,但如果你没有它,你可以安装它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

and finally the output is... the Stackoverflow logo!!!

最后输出是…… Stackoverflow 标志!!!

enter image description here

在此处输入图片说明

Now of course this would be overkill for just grabbing a static image but if your want to grab something that requires Javascript to get to this could be a viable solution.

当然,这对于仅抓取静态图像来说是多余的,但是如果您想抓取需要 Javascript 才能到达的东西,这可能是一个可行的解决方案。

回答by eugene-bright

I wrote this useful python3 function.

我写了这个有用的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()

It returns png image of displayed element as bytes. Limitation: element must fit in viewport.
You must install wand module to work with it.

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

回答by SEDaradji

Here is a function that does just that, The sizes must be casted to integers before being passed to the crop function :

这是一个执行此操作的函数,在传递给裁剪函数之前,必须将大小转换为整数:

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

回答by Iman Kermani

Worked for me in python3.5

在 python3.5 中为我工作

from selenium import webdriver


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

回答by StackG

Expanding on the comments in response to RandomPhobia's very nice answer, here are two solutions with correct import statements that will open a full-screen screenshot without first saving to a file:

扩展评论以响应 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()))

And because I'm sure your next question is, "Well that's great but which one is fastest?", here's how to determine it (I find the first method to be the fastest by some distance):

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

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)

回答by Gavriel Cohen

Screenshot by Element:

元素截图:

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

回答by Fernando Wittmann

I converted @randomphobia's answer into a function. I also used @bummis' suggestion of using location_once_scrolled_into_viewinstead of locationin order to generalize no matter the size of the page.

我将@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

Here's a gist: https://gist.github.com/WittmannF/b714d3ceb7b6a5cd50002f11fb5a4929

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