【问题标题】:How to take partial screenshot with Selenium WebDriver in python?如何在 python 中使用 Selenium WebDriver 截取部分截图?
【发布时间】:2013-02-07 17:28:25
【问题描述】:

我为此搜索了很多,但找不到解决方案。这是a similar question,在 java 中有一个可能的解决方案。

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

【问题讨论】:

    标签: python selenium


    【解决方案1】:

    除了 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
    

    最后的输出是...... Stackoverflow 标志!!!

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

    【讨论】:

    • 也可以直接获取内存中的截图:img = Image.open(StringIO(base64.decodestring(driver.get_screenshot_as_base64())))
    • 内存中加载的替代方法是img = fox.get_screenshot_as_png(),然后img = Image.open(StringIO(img)) 将其加载为 PIL 图像。
    • 来自@sukrit-gupta 的 NAA 的评论:RandomPhobia,在不需要滚动的静态页面的情况下,您的答案非常有用。如果有人需要从需要滚动的大页面中获取图像,您应该使用 location_once_scrolled_into_view 函数。因此,将 location = element.location 替换为: location = img.location_once_scrolled_into_view 另外,请确保使用 Chrome 而不是 Firefox,因为 Chrome 只截取可见区域的屏幕截图,而 Firefox 截取整个选项卡的屏幕截图。跨度>
    • 跟进@yellowcap 的建议:注意在Python 3+ 中,你应该BytesIO 而不是StringIO
    • 我正面临调整大小问题,而图像被缩小。屏幕截图正在工作,但裁剪图像似乎不起作用。有没有人遇到过同样的情况?
    【解决方案2】:

    在 python3.5 中为我工作

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

    附言

    保存到文件

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

    【讨论】:

    • @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 你们可以做image = driver.find_element_by_id('el_id').screenshot(output_file_path)。 API文档请参考here
    【解决方案3】:

    我写了这个有用的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 图像。 限制:元素必须适合视口。
    您必须安装 wand 模块才能使用它。

    【讨论】:

    • 不错的代码!当我在 chrome 中尝试使用长页面时,我认为 x = element.location_once_scrolled_into_view["x"] y = element.location_once_scrolled_into_view["y"] 因为 location 可能会返回比窗口大的 y。
    【解决方案4】:

    这是一个功能,在传递给裁剪函数之前,大小必须转换为整数:

    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 的要求使用 Selenium。
    • 它确实使用了selenium,但是这里不需要import语句,它还包括位置从float到int的转换,如果位置不是整数,函数img.crop会抛出异常跨度>
    • TypeError: initial_value must be str or None, not bytes
    • 你的 print(img) 是什么,是方法还是字节对象?
    • 我不确定我是否理解您的问题
    【解决方案5】:

    为了响应 RandomPhobia 的非常好的答案,扩展 cmets,这里有两个具有正确导入语句的解决方案,它们将打开全屏屏幕截图而无需先保存到文件:

    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)
    

    【讨论】:

      【解决方案6】:

      元素截图:

      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)
      • @MostafaGhadimi 请检查:sqa.stackexchange.com/questions/40321/…
      【解决方案7】:

      就这么简单:

      element = driver.find_element_by_class_name('myclass')
      element.screenshot('screenshot.png')
      

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          猜你喜欢
          • 2012-06-06
          • 1970-01-01
          • 1970-01-01
          • 2018-05-21
          • 2022-07-01
          • 2011-03-26
          • 1970-01-01
          相关资源
          最近更新 更多