【问题标题】:Transparent screenshot with headless ChromeDriver via Selenium通过 Selenium 使用无头 ChromeDriver 的透明屏幕截图
【发布时间】:2018-03-21 06:19:40
【问题描述】:

据我了解,ChromeDriver 本身不会设置背景,CSS 会。因此,如果背景是透明的,为什么我没有得到透明的截图?

这是所谓透明网站的截图: 相同的屏幕截图,但在背景中有一个红色 div 以显示透明度应该位于的位置:

这是我的代码:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from datetime import datetime

options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome(chrome_options=options)

driver.set_window_size(2560, 1600)
driver.get('https://twitter.com/realDonaldTrump/status/516382177798680576')
# driver.execute_script("$('body').append(`<div style='background: red; width: 100%; height: 100%;'></div>`);")
driver.save_screenshot('screenshots/' + str(datetime.now()) + '.png')

driver.quit()

我如何才能创建该屏幕截图的透明版本?

*** 编辑 *** 我大致说明了我是如何做到这一点的。接受的答案帮助我达到了可以弄清楚的地步,这就是我想要的。然而,这个要点是我的问题的正确解决方案: https://gist.github.com/colecrtr/f58834ff09ab07e3c1164667b753e77a

【问题讨论】:

  • 您评论的那一行,您是否尝试更改为这样的内容:driver.execute_script("$('body').css('background-color', 'transparent');")?请注意,所有 div 层都必须为background-color: transparent 才能拥有真正透明的背景,因此如果仅通过更改主体背景颜色不起作用,则必须使用开发人员工具进行一些测试和调整。还要记住,页面必须有 jQuery,我不认为 twitter 有,但我不太确定。
  • @ChristosLytras 我尝试将background-color 设置为transparent,但它仍然导致白色背景。 Twitter 确实使用了 jQuery。我将如何调整开发者工具?
  • 浏览推特时按F12,进入元素选项卡,然后检查内容的每个DIV子元素的样式以获取背景颜色属性。
  • 很遗憾,要点的链接被破坏了。
  • @BradRoot 我最近更改了我的用户名,这破坏了链接。我已将其更新为我的新用户名 :-)

标签: python-3.x selenium selenium-chromedriver


【解决方案1】:

一种方法是将屏幕截图中的每个白色像素转换为透明像素,方法是将 alpha 字节设置为 0:

from selenium import webdriver
from PIL import Image
from io import BytesIO # python 3
import numpy as np

def remove_color(img, rgba):
  data = np.array(img.convert('RGBA'))        # rgba array from image
  pixels = data.view(dtype=np.uint32)[...,0]  # pixels as rgba uint32
  data[...,3] = np.where(pixels == np.uint32(rgba), np.uint8(0), np.uint8(255))  # set alpha channel
  return Image.fromarray(data)

driver = webdriver.Chrome()
driver.get("http://www.bbc.co.uk/news")

# take screenshot with a transparent background
with Image.open(BytesIO(driver.get_screenshot_as_png())) as img :
  with remove_color(img, 0xffffffff) as img2:
    img2.save(r"C:\temp\screenshot.png")

但是,如果页面内容有一些白色像素并且抗锯齿可能是可见的,那么您最终可能会得到一些意想不到的透明像素。

另一种解决方案是使用带有 Chrome 的 DevTool API 从屏幕截图中排除背景:

from selenium import webdriver
import json

def send(cmd, params={}):
  resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id
  url = driver.command_executor._url + resource
  body = json.dumps({'cmd':cmd, 'params': params})
  response = driver.command_executor._request('POST', url, body)
  if response['status']: raise Exception(response.get('value'))
  return response.get('value')

options = webdriver.ChromeOptions()
options.add_argument("disable-gpu")
options.add_argument("disable-infobars")

driver = webdriver.Chrome(chrome_options=options)
driver.get("http://www.bbc.co.uk/news")

# take screenshot with a transparent background
send("Emulation.setDefaultBackgroundColorOverride", {'color': {'r': 0, 'g': 0, 'b': 0, 'a': 0}})
driver.get_screenshot_as_file(r"C:\temp\screenshot.png")
send("Emulation.setDefaultBackgroundColorOverride")  # restore

【讨论】:

  • 是的,第二种解决方案对我有用。多亏了 Tabun 的评论,我才明白了这一点,但我会将其标记为正确,以备将来发现。
  • @Cole,我是导致此解决方案的评论的作者。
  • 我的错,我现在明白了。非常感谢!
【解决方案2】:

png 可以有透明像素,但屏幕截图不能。每当您渲染某些东西时,您都会查看图层的透明度级别来混合渲染,但组合图层将始终具有背景。

屏幕截图是在屏幕上呈现的内容,它永远不会是透明的。如何在桌面上显示真正的透明图像?你不能,因为桌面背景或其他东西总是必须在那里。

所以你问的和Chrome、ChromeDriver无关。任何截屏工具都无法截取透明的截屏,除非你告诉它要屏蔽什么。

即使是像 Photoshop 这样的工具也使用特殊的方式(带有细微变化的灰色框)来显示透明背景,但是如果您使用屏幕截图工具来捕获该图像,结果将是具有实际像素且没有透明度的图像,如下所示

【讨论】:

  • 好点,我理解这一点,但只要没有定义背景或背景本身被定义为透明,使用 PhantomJS 驱动程序就会产生透明图像。因此我知道这是可能的,这只是 ChromeDriver 的问题,因为其他驱动程序无法正确呈现页面。
  • 试试 chrome headless 看看它是否改变,因为所有实际呈现在屏幕上的都会给你一个背景颜色。 PhantomJS 作为内存渲染器不需要有一个后台容器来渲染和降低透明度
  • 截图可以有透明背景。例如puppeteer 提供选项。使用 Selenium 可以通过从 PNG 中删除背景或使用 Chrome 使用自定义命令调用 Emulation.setDefaultBackgroundColorOverride
  • @FlorentB.,这是使用 Chrome 调试器 API 而不是 Selenium
  • 可以使用 Selenium 调用 Chrome 调试器 API。
猜你喜欢
  • 1970-01-01
  • 2011-11-13
  • 2020-09-12
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多