使用 Selenium Python 和 chromedriver 对整个页面进行截图
- 2025-03-20 08:46:00
- admin 原创
- 44
问题描述:
尝试了各种方法后......我偶然发现了这个页面,可以使用 chromedriver、selenium 和 python 截取整页截图。
原始代码在这里。(我将代码复制到下面的帖子中)
它使用 PIL,效果很好!但是,有一个问题……它会捕获整个页面的固定标题和重复内容,并且在页面切换期间也会错过页面的某些部分。截取屏幕截图的示例 URL:
http://www.w3schools.com/js/default.asp
如何避免使用此代码重复标题...或者是否有更好的选择,仅使用 python...... (我不懂 java 并且不想使用 java)。
请参阅下面的当前结果和示例代码的屏幕截图。
测试.py
"""
This script uses a simplified version of the one here:
https://snipt.net/restrada/python-selenium-workaround-for-full-page-screenshot-using-chromedriver-2x/
It contains the *crucial* correction added in the comments by Jason Coutu.
"""
import sys
from selenium import webdriver
import unittest
import util
class Test(unittest.TestCase):
""" Demonstration: Get Chrome to generate fullscreen screenshot """
def setUp(self):
self.driver = webdriver.Chrome()
def tearDown(self):
self.driver.quit()
def test_fullpage_screenshot(self):
''' Generate document-height screenshot '''
#url = "http://effbot.org/imagingbook/introduction.htm"
url = "http://www.w3schools.com/js/default.asp"
self.driver.get(url)
util.fullpage_screenshot(self.driver, "test.png")
if __name__ == "__main__":
unittest.main(argv=[sys.argv[0]])
工具类
import os
import time
from PIL import Image
def fullpage_screenshot(driver, file):
print("Starting chrome full page screenshot workaround ...")
total_width = driver.execute_script("return document.body.offsetWidth")
total_height = driver.execute_script("return document.body.parentNode.scrollHeight")
viewport_width = driver.execute_script("return document.body.clientWidth")
viewport_height = driver.execute_script("return window.innerHeight")
print("Total: ({0}, {1}), Viewport: ({2},{3})".format(total_width, total_height,viewport_width,viewport_height))
rectangles = []
i = 0
while i < total_height:
ii = 0
top_height = i + viewport_height
if top_height > total_height:
top_height = total_height
while ii < total_width:
top_width = ii + viewport_width
if top_width > total_width:
top_width = total_width
print("Appending rectangle ({0},{1},{2},{3})".format(ii, i, top_width, top_height))
rectangles.append((ii, i, top_width,top_height))
ii = ii + viewport_width
i = i + viewport_height
stitched_image = Image.new('RGB', (total_width, total_height))
previous = None
part = 0
for rectangle in rectangles:
if not previous is None:
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1]))
print("Scrolled To ({0},{1})".format(rectangle[0], rectangle[1]))
time.sleep(0.2)
file_name = "part_{0}.png".format(part)
print("Capturing {0} ...".format(file_name))
driver.get_screenshot_as_file(file_name)
screenshot = Image.open(file_name)
if rectangle[1] + viewport_height > total_height:
offset = (rectangle[0], total_height - viewport_height)
else:
offset = (rectangle[0], rectangle[1])
print("Adding to stitched image with offset ({0}, {1})".format(offset[0],offset[1]))
stitched_image.paste(screenshot, offset)
del screenshot
os.remove(file_name)
part = part + 1
previous = rectangle
stitched_image.save(file)
print("Finishing chrome full page screenshot workaround...")
return True
解决方案 1:
该答案改进了am05mhz和Javed Karim之前的答案。
它假定无头模式,并且最初未设置窗口大小选项。在调用此函数之前,请确保页面已完全或充分加载。
它会尝试将宽度和高度设置为必要的值。整个页面的屏幕截图有时会包含不必要的垂直滚动条。避免出现滚动条的一种方法是截取 body 元素的屏幕截图。保存屏幕截图后,它会将大小恢复到原来的大小,否则下一个屏幕截图的大小可能无法正确设置。
最终,对于某些示例来说,这种技术可能仍然无法完美地发挥作用。
from selenium import webdriver
def save_screenshot(driver: webdriver.Chrome, path: str = '/tmp/screenshot.png') -> None:
# Ref: https://stackoverflow.com/a/52572919/
original_size = driver.get_window_size()
required_width = driver.execute_script('return document.body.parentNode.scrollWidth')
required_height = driver.execute_script('return document.body.parentNode.scrollHeight')
driver.set_window_size(required_width, required_height)
# driver.save_screenshot(path) # has scrollbar
driver.find_element_by_tag_name('body').screenshot(path) # avoids scrollbar
driver.set_window_size(original_size['width'], original_size['height'])
如果使用的 Python 版本早于 3.6,请从函数定义中删除类型注释。
解决方案 2:
屏幕截图仅限于视口,但您可以通过捕获body
元素来解决这个问题,因为即使元素大于视口,webdriver 也会捕获整个元素。这样就不必处理滚动和拼接图像,但您可能会看到页脚位置的问题(如下面的屏幕截图所示)。
已在装有 Chrome 驱动程序的 Windows 8 和 Mac High Sierra 上进行测试。
from selenium import webdriver
url = 'https://stackoverflow.com/'
path = '/path/to/save/in/scrape.png'
driver = webdriver.Chrome()
driver.get(url)
el = driver.find_element_by_tag_name('body')
el.screenshot(path)
driver.quit()
返回:(全尺寸:https://i.sstatic.net/ppDiI.png)
解决方案 3:
工作原理:将浏览器高度设置为尽可能长......
#coding=utf-8
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def test_fullpage_screenshot(self):
# please note that we MUST use headless mode
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--start-maximized')
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get("yoururlxxx")
time.sleep(2)
height = driver.execute_script('return document.documentElement.scrollHeight')
width = driver.execute_script('return document.documentElement.scrollWidth')
driver.set_window_size(width, height) # the trick
time.sleep(2)
driver.save_screenshot("screenshot1.png")
driver.quit()
if __name__ == "__main__":
test_fullpage_screenshot()
解决方案 4:
关键是开启headless
模式!无需拼接,也无需加载两次页面。
完整工作代码:
URL = 'http://www.w3schools.com/js/default.asp'
options = webdriver.ChromeOptions()
options.headless = True
driver = webdriver.Chrome(options=options)
driver.get(URL)
S = lambda X: driver.execute_script('return document.body.parentNode.scroll'+X)
driver.set_window_size(S('Width'),S('Height')) # May need manual adjustment
driver.find_element_by_tag_name('body').screenshot('web_screenshot.png')
driver.quit()
这实际上与@Acumenus发布的代码相同,但略有改进。
我的发现摘要
我还是决定把这个发布出来,因为我没有找到关于headless
关闭模式(显示浏览器)以便截屏时会发生什么的解释。经我测试(使用 Chrome WebDriver),如果headless
打开该模式,则屏幕截图将按预期保存。但是,如果headless
关闭该模式,保存的屏幕截图具有大致正确的宽度和高度,但结果因情况而异。通常,屏幕上可见的页面上部会被保存,但图像的其余部分只是纯白色。还有一种情况是尝试使用上面的链接保存这个 Stack Overflow 线程;甚至上部也没有保存,有趣的是它现在是透明的,而其余部分仍然是白色的。我注意到的最后一个案例只出现在给定的W3Schools链接中一次;那里没有白色部分,但页面的上部一直重复到最后,包括标题。
我希望这能帮助那些由于某种原因没有得到预期结果的人,因为我没有看到任何人明确解释headless
这种简单方法对模式的要求。只有当我自己发现这个问题的解决方案时,我才发现@vc2279的一篇文章 提到无头浏览器的窗口可以设置为任意大小(对于相反的情况似乎也是如此)。不过,我文章中的解决方案对此进行了改进,它不需要重复打开浏览器/驱动程序或重新加载页面。
进一步的建议
如果对于某些页面,它不适合您,我建议尝试time.sleep(seconds)
在获取页面大小之前添加。另一种情况是,如果页面需要滚动到底部才能加载更多内容,可以通过scheight
此帖子中的方法解决:
scheight = .1
while scheight < 9.9:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight/%s);" % scheight)
scheight += .01
另外,请注意,对于某些页面,内容可能不在任何顶级 HTML 标记(如<html>
或)中<body>
,例如,YouTube使用<ytd-app>
标记。最后要说的是,我发现一个页面“返回”的屏幕截图仍然带有水平滚动条,窗口大小需要手动调整,即图像宽度需要增加 18 个像素,如下所示:S('Width')+18
。
解决方案 5:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('https://developer.mozilla.org/')
element = driver.find_element_by_tag_name('body')
element_png = element.screenshot_as_png
with open("test2.png", "wb") as file:
file.write(element_png)
这对我来说很管用。它将整个页面保存为屏幕截图。有关更多信息,您可以阅读 api 文档:
http://selenium-python.readthedocs.io/api.html
解决方案 6:
了解了@Moshisho 的方法后。
我的完整独立工作脚本是......(每次滚动和定位后添加睡眠 0.2)
import sys
from selenium import webdriver
import util
import os
import time
from PIL import Image
def fullpage_screenshot(driver, file):
print("Starting chrome full page screenshot workaround ...")
total_width = driver.execute_script("return document.body.offsetWidth")
total_height = driver.execute_script("return document.body.parentNode.scrollHeight")
viewport_width = driver.execute_script("return document.body.clientWidth")
viewport_height = driver.execute_script("return window.innerHeight")
print("Total: ({0}, {1}), Viewport: ({2},{3})".format(total_width, total_height,viewport_width,viewport_height))
rectangles = []
i = 0
while i < total_height:
ii = 0
top_height = i + viewport_height
if top_height > total_height:
top_height = total_height
while ii < total_width:
top_width = ii + viewport_width
if top_width > total_width:
top_width = total_width
print("Appending rectangle ({0},{1},{2},{3})".format(ii, i, top_width, top_height))
rectangles.append((ii, i, top_width,top_height))
ii = ii + viewport_width
i = i + viewport_height
stitched_image = Image.new('RGB', (total_width, total_height))
previous = None
part = 0
for rectangle in rectangles:
if not previous is None:
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1]))
time.sleep(0.2)
driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');")
time.sleep(0.2)
print("Scrolled To ({0},{1})".format(rectangle[0], rectangle[1]))
time.sleep(0.2)
file_name = "part_{0}.png".format(part)
print("Capturing {0} ...".format(file_name))
driver.get_screenshot_as_file(file_name)
screenshot = Image.open(file_name)
if rectangle[1] + viewport_height > total_height:
offset = (rectangle[0], total_height - viewport_height)
else:
offset = (rectangle[0], rectangle[1])
print("Adding to stitched image with offset ({0}, {1})".format(offset[0],offset[1]))
stitched_image.paste(screenshot, offset)
del screenshot
os.remove(file_name)
part = part + 1
previous = rectangle
stitched_image.save(file)
print("Finishing chrome full page screenshot workaround...")
return True
driver = webdriver.Chrome()
''' Generate document-height screenshot '''
url = "http://effbot.org/imagingbook/introduction.htm"
url = "http://www.w3schools.com/js/default.asp"
driver.get(url)
fullpage_screenshot(driver, "test1236.png")
解决方案 7:
不确定大家是否还遇到这个问题。我做了一个小改动,效果很好,可以很好地与动态区域配合使用。希望它能有所帮助
# 1. get dimensions
browser = webdriver.Chrome(chrome_options=options)
browser.set_window_size(default_width, default_height)
browser.get(url)
time.sleep(sometime)
total_height = browser.execute_script("return document.body.parentNode.scrollHeight")
browser.quit()
# 2. get screenshot
browser = webdriver.Chrome(chrome_options=options)
browser.set_window_size(default_width, total_height)
browser.get(url)
browser.save_screenshot(screenshot_path)
解决方案 8:
为什么不直接获取页面的宽度和高度,然后调整驱动程序的大小?那么会是这样的
total_width = driver.execute_script("return document.body.offsetWidth")
total_height = driver.execute_script("return document.body.scrollHeight")
driver.set_window_size(total_width, total_height)
driver.save_screenshot("SomeName.png")
这将截取整个页面的屏幕截图,而无需将不同部分合并在一起。
解决方案 9:
对于 Chrome,也可以使用Chrome DevTools 协议:
import base64
...
page_rect = browser.driver.execute_cdp_cmd("Page.getLayoutMetrics", {})
screenshot = browser.driver.execute_cdp_cmd(
"Page.captureScreenshot",
{
"format": "png",
"captureBeyondViewport": True,
"clip": {
"width": page_rect["contentSize"]["width"],
"height": page_rect["contentSize"]["height"],
"x": 0,
"y": 0,
"scale": 1
}
})
with open(path, "wb") as file:
file.write(base64.urlsafe_b64decode(screenshot["data"]))
致谢
这在无头模式和非无头模式下均有效。
解决方案 10:
您可以通过更改屏幕截图之前的标题 CSS 来实现这一点:
topnav = driver.find_element_by_id("topnav")
driver.execute_script("arguments[0].setAttribute('style', 'position: absolute; top: 0px;')", topnav)
编辑:将此行放在窗口滚动后:
driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');")
因此在你的util.py中它将是:
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1]))
driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');")
如果网站使用header
标签,你可以这样做find_element_by_tag_name("header")
解决方案 11:
我为 Python 3.6 更改了代码,也许对某些人有用:
from selenium import webdriver
from sys import stdout
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import unittest
#from Login_Page import Login_Page
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
from io import BytesIO
from PIL import Image
def testdenovoUIavailable(self):
binary = FirefoxBinary("C:\\Mozilla Firefox\\firefox.exe")
self.driver = webdriver.Firefox(firefox_binary=binary)
verbose = 0
#open page
self.driver.get("http://yandex.ru")
#hide fixed header
#js_hide_header=' var x = document.getElementsByClassName("topnavbar-wrapper ng-scope")[0];x[\'style\'] = \'display:none\';'
#self.driver.execute_script(js_hide_header)
#get total height of page
js = 'return Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);'
scrollheight = self.driver.execute_script(js)
if verbose > 0:
print(scrollheight)
slices = []
offset = 0
offset_arr=[]
#separate full screen in parts and make printscreens
while offset < scrollheight:
if verbose > 0:
print(offset)
#scroll to size of page
if (scrollheight-offset)<offset:
#if part of screen is the last one, we need to scroll just on rest of page
self.driver.execute_script("window.scrollTo(0, %s);" % (scrollheight-offset))
offset_arr.append(scrollheight-offset)
else:
self.driver.execute_script("window.scrollTo(0, %s);" % offset)
offset_arr.append(offset)
#create image (in Python 3.6 use BytesIO)
img = Image.open(BytesIO(self.driver.get_screenshot_as_png()))
offset += img.size[1]
#append new printscreen to array
slices.append(img)
if verbose > 0:
self.driver.get_screenshot_as_file('screen_%s.jpg' % (offset))
print(scrollheight)
#create image with
screenshot = Image.new('RGB', (slices[0].size[0], scrollheight))
offset = 0
offset2= 0
#now glue all images together
for img in slices:
screenshot.paste(img, (0, offset_arr[offset2]))
offset += img.size[1]
offset2+= 1
screenshot.save('test.png')
解决方案 12:
来源:https ://pypi.org/project/Selenium-Screenshot/
from Screenshot import Screenshot_Clipping
from selenium import webdriver
import time
ob = Screenshot_Clipping.Screenshot()
driver = webdriver.Chrome()
url = "https://www.bbc.com/news/world-asia-china-51108726"
driver.get(url)
time.sleep(1)
img_url = ob.full_Screenshot(driver, save_path=r'.', image_name='Myimage.png')
driver.quit()
解决方案 13:
全页面截图不属于W3C 规范。但是,许多 Web 驱动程序会实现自己的端点来获取真正的全页面截图。我发现使用 geckodriver 的这种方法比注入的“截图、滚动、拼接”方法要好得多,而且比在无头模式下调整窗口大小要好得多。
例子:
from selenium import webdriver
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.firefox.options import Options
options = Options()
options.headless = True
service = Service('/your/path/to/geckodriver')
driver = webdriver.Firefox(options=options, service=service)
driver.get('https://www.nytimes.com/')
driver.get_full_page_screenshot_as_file('example.png')
driver.close()
geckodriver(火狐浏览器)
如果您使用 geckodriver,您可以使用以下方法:
driver.get_full_page_screenshot_as_file
driver.save_full_page_screenshot
driver.get_full_page_screenshot_as_png
driver.get_full_page_screenshot_as_base64
我已经测试并确认这些可以在Selenium 4.07上运行。我不相信这些功能包含在 Selenium 3 中。
我能找到的关于这些的最佳文档就在这个合并中
chromedriver(Chromium)
看来 chromedriver 已经实现了他们自己的整页截图功能:
https://chromium-review.googlesource.com/c/chromium/src/+/2300980
Selenium 团队似乎正致力于在 Selenium 4 中提供支持:
https://github.com/SeleniumHQ/selenium/issues/8168
解决方案 14:
这是我在 StackOverflow 上的第一个回答。我是新手。同行专家程序员引用的其他回答都很棒,我甚至没有参加比赛。我只想引用以下链接中的步骤:pypi.org
请参阅整页截图部分。
打开命令提示符并导航到 Python 的安装目录
cd "enter the directory"
使用 pip 安装模块
pip install Selenium-Screenshot
上述模块适用于 Python 3。安装模块后,通过在 Python IDLE 中创建单独的文件尝试以下代码
from Screenshot import Screenshot_Clipping
from selenium import webdriver
ob = Screenshot_Clipping.Screenshot()
driver = webdriver.Chrome()
url = "https://github.com/sam4u3/Selenium_Screenshot/tree/master/test"
driver.get(url)
# the line below makes taking & saving screenshots very easy.
img_url=ob.full_Screenshot(driver, save_path=r'.', image_name='Myimage.png')
print(img_url)
driver.close()
driver.quit()
解决方案 15:
稍微修改@ihightower 和@A.Minachev 的代码,使其在 mac retina 上运行:
import time
from PIL import Image
from io import BytesIO
def fullpage_screenshot(driver, file, scroll_delay=0.3):
device_pixel_ratio = driver.execute_script('return window.devicePixelRatio')
total_height = driver.execute_script('return document.body.parentNode.scrollHeight')
viewport_height = driver.execute_script('return window.innerHeight')
total_width = driver.execute_script('return document.body.offsetWidth')
viewport_width = driver.execute_script("return document.body.clientWidth")
# this implementation assume (viewport_width == total_width)
assert(viewport_width == total_width)
# scroll the page, take screenshots and save screenshots to slices
offset = 0 # height
slices = {}
while offset < total_height:
if offset + viewport_height > total_height:
offset = total_height - viewport_height
driver.execute_script('window.scrollTo({0}, {1})'.format(0, offset))
time.sleep(scroll_delay)
img = Image.open(BytesIO(driver.get_screenshot_as_png()))
slices[offset] = img
offset = offset + viewport_height
# combine image slices
stitched_image = Image.new('RGB', (total_width * device_pixel_ratio, total_height * device_pixel_ratio))
for offset, image in slices.items():
stitched_image.paste(image, (0, offset * device_pixel_ratio))
stitched_image.save(file)
fullpage_screenshot(driver, 'test.png')
解决方案 16:
对于使用 Selenium 4 和 Chrome 驱动程序的 Python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
import time
import shutil
def take_full_page_screenshot():
#Install chrome driver
chrome_driver_path = ChromeDriverManager().install()
service = Service(chrome_driver_path)
service.start()
#setup chrome options
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--incognito')
options.add_argument('--start-maximized')
options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_driver_path, options=options)
#open url and wait for the page to load
driver.get('https://www.stackoverflow.com')
time.sleep(2)
#find the element with longest height on page
element = driver.find_element(By.TAG_NAME, 'body')
total_height = element.size["height"]+1000
#set the window dimensions
driver.set_window_size(1920, total_height)
#save screenshot
driver.save_screenshot("screenshot.png")
#quit driver
driver.quit()
if __name__ == '__main__':
take_full_page_screenshot()
解决方案 17:
element=driver.find_element_by_tag_name('body')
element_png = element.screenshot_as_png
with open("test2.png", "wb") as file:
file.write(element_png)
之前建议的代码第 2 行有错误。这是更正后的代码。作为新手,目前还不能编辑我自己的帖子。
有时 baove 无法获得最佳效果。因此可以使用另一种方法获取所有元素的高度并将它们相加以设置捕获高度,如下所示:
element=driver.find_elements_by_xpath("/html/child::*/child::*")
eheight=set()
for e in element:
eheight.add(round(e.size["height"]))
print (eheight)
total_height = sum(eheight)
driver.execute_script("document.getElementsByTagName('html')[0].setAttribute('style', 'height:"+str(total_height)+"px')")
element=driver.find_element_by_tag_name('body')
element_png = element.screenshot_as_png
with open(fname, "wb") as file:
file.write(element_png)
顺便说一句,它在 FF 上运行。
解决方案 18:
您可以使用Splinter
Splinter 是现有浏览器自动化工具(如 Selenium)之上的抽象层,新版本中
有一项新功能。选项将为您进行全屏捕获。browser.screenshot(..., full=True)
`0.10.0`
full=True
解决方案 19:
使用 python 比较简单,但速度较慢
import os
from selenium import webdriver
from PIL import Image
def full_screenshot(driver: webdriver):
driver.execute_script(f"window.scrollTo({0}, {0})")
total_width = driver.execute_script("return document.body.offsetWidth")
total_height = driver.execute_script("return document.body.parentNode.scrollHeight")
viewport_width = driver.execute_script("return document.body.clientWidth")
viewport_height = driver.execute_script("return window.innerHeight")
rectangles = []
i = 0
while i < total_height:
ii = 0
top_height = i + viewport_height
if top_height > total_height:
top_height = total_height
while ii < total_width:
top_width = ii + viewport_width
if top_width > total_width:
top_width = total_width
rectangles.append((ii, i, top_width, top_height))
ii = ii + viewport_width
i = i + viewport_height
stitched_image = Image.new('RGB', (total_width, total_height))
previous = None
part = 0
for rectangle in rectangles:
if not previous is None:
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1]))
file_name = "part_{0}.png".format(part)
driver.get_screenshot_as_file(file_name)
screenshot = Image.open(file_name)
if rectangle[1] + viewport_height > total_height:
offset = (rectangle[0], total_height - viewport_height)
else:
offset = (rectangle[0], rectangle[1])
stitched_image.paste(screenshot, offset)
del screenshot
os.remove(file_name)
part = part + 1
previous = rectangle
return stitched_image
解决方案 20:
我修改了@ihightower 给出的答案,不再在该函数中保存屏幕截图,而是返回网页的总高度和总宽度,然后将窗口大小设置为总高度和总宽度。
from PIL import Image
from io import BytesIO
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def open_url(url):
options = Options()
options.headless = True
driver = webdriver.Chrome(chrome_options=options)
driver.maximize_window()
driver.get(url)
save_screenshot(driver, 'screen.png')
def save_screenshot(driver, file_name):
height, width = scroll_down(driver)
driver.set_window_size(width, height)
img_binary = driver.get_screenshot_as_png()
img = Image.open(BytesIO(img_binary))
img.save(file_name)
# print(file_name)
print(" screenshot saved ")
def scroll_down(driver):
total_width = driver.execute_script("return document.body.offsetWidth")
total_height = driver.execute_script("return document.body.parentNode.scrollHeight")
viewport_width = driver.execute_script("return document.body.clientWidth")
viewport_height = driver.execute_script("return window.innerHeight")
rectangles = []
i = 0
while i < total_height:
ii = 0
top_height = i + viewport_height
if top_height > total_height:
top_height = total_height
while ii < total_width:
top_width = ii + viewport_width
if top_width > total_width:
top_width = total_width
rectangles.append((ii, i, top_width, top_height))
ii = ii + viewport_width
i = i + viewport_height
previous = None
part = 0
for rectangle in rectangles:
if not previous is None:
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1]))
time.sleep(0.5)
# time.sleep(0.2)
if rectangle[1] + viewport_height > total_height:
offset = (rectangle[0], total_height - viewport_height)
else:
offset = (rectangle[0], rectangle[1])
previous = rectangle
return (total_height, total_width)
open_url("https://www.medium.com")
解决方案 21:
我目前正在使用这种方法:
def take_screenshot(self, driver, screenshot_name = "debug.png"):
elem = driver.find_element_by_tag_name('body')
total_height = elem.size["height"] + 1000
driver.set_window_size(1920, total_height)
time.sleep(2)
driver.save_screenshot(screenshot_name)
return driver
解决方案 22:
如果您尝试在~2021 中执行此帖子,则需要从以下位置编辑查找元素命令:
element = driver.find_element_by_tag('body')
到:
from selenium.webdriver.common.by import By
...
element = driver.find_element(By.TAG_NAME, "body")
解决方案 23:
我已修改jeremie-s' 的答案,以便它只获取一次 url。
browser = webdriver.Chrome(chrome_options=options)
browser.set_window_size(default_width, default_height)
browser.get(url)
height = browser.execute_script("return document.body.parentNode.scrollHeight")
# 2. get screenshot
browser.set_window_size(default_width, height)
browser.save_screenshot(screenshot_path)
browser.quit()
解决方案 24:
明白了!效果非常好
对于 NodeJS,但概念是一样的:
await driver.executeScript(`
document.documentElement.style.display = "table";
document.documentElement.style.width = "100%";
document.body.style.display = "table-row";
`);
await driver.findElement(By.css('body')).takeScreenshot();
解决方案 25:
这对我有用
s = Service("/opt/homebrew/bin/chromedriver")
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--start-maximized')
driver = webdriver.Chrome(chrome_options=chrome_options, service=s)
highest_ele = driver.find_element(By.XPATH, '//*[@id="react-app"]/div[3]/div[3]/span/span/span[2]')
total_height = highest_ele.location['y']
driver.set_window_size(height=total_height, width=1920)
time.sleep(1)
driver.save_screenshot('~/shot.png') # replace your path
解决方案 26:
在最新发布的 Selenium 版本 4.16 中,您需要以不同的方式配置无头模式。例如:
options.add_argument("--headless=new")
我已将截取全尺寸屏幕截图的完整代码留在了我的 GitHub 页面上:
使用 Selenium 实现全尺寸网页截图自动化
解决方案 27:
正确答案是使用Selenium-Screenshot。不要重新发明轮子。
如何使用:
pip install Selenium-Screenshot
然后在您的代码中添加:
from Screenshot import Screenshot
from selenium import webdriver
driver = webdriver.Chrome()
ob = Screenshot.Screenshot()
ob.full_screenshot(driver, save_path="screenshots", image_name="test.png")
这会将整个页面的 PNG 保存到当前工作目录中的test.png
文件夹中。screenshots
它还将支持其他驱动程序,例如 SeleniumBase 的uc或Undetected-Chromedriver 模式,使机器人看起来像人类。
from seleniumbase import Driver
from Screenshot import Screenshot
driver = Driver(uc=True, browser="chrome")
ob = Screenshot.Screenshot()
ob.full_screenshot(driver, save_path="screenshots", image_name=image_name)
扫码咨询,免费领取项目管理大礼包!