Сделайте скриншот полной страницы с помощью Selenium Python с хромедрайвером
После опробования различных подходов... Я наткнулся на эту страницу, чтобы сделать полный снимок экрана с chromedriver, selenium и python.
оригинальный код здесь: http://seleniumpythonqa.blogspot.com/2015/08/generate-full-page-screenshot-in-chrome.html (и я копирую код в этой публикации ниже)
Он использует PIL и прекрасно работает!!!!! Однако есть одна проблема... она фиксирует фиксированные заголовки и повторяется для всей страницы, а также пропускает некоторые части страницы во время смены страницы. Пример URL для скриншота:
http://www.w3schools.com/js/default.asp
Как избежать повторяющихся заголовков с этим кодом... Или есть ли лучший вариант, который использует только Python... (Я не знаю Java и не хочу использовать Java).
Пожалуйста, смотрите скриншот текущего результата и пример кода ниже.
test.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]])
util.py
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
25 ответов
Вы можете добиться этого, изменив 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")
Этот ответ улучшается после предыдущих ответов от am05mhz и Javed Karim.
Предполагается, что безголовый режим и что опция размера окна изначально не была установлена. Перед вызовом этой функции убедитесь, что страница загружена полностью или достаточно.
Он пытается установить ширину и высоту как то, что необходимо. Скриншот всей страницы может иногда включать ненужную вертикальную полосу прокрутки. Один из способов вообще избежать полосы прокрутки - сделать скриншот элемента body. После сохранения снимка экрана он возвращается к первоначальному размеру, в противном случае размер следующего снимка экрана может быть задан неправильно.
В конечном счете, этот метод все еще может работать не совсем хорошо для некоторых примеров.
def save_screenshot(driver: webdriver.Chrome, path: str = '/tmp/screenshot.png'):
# Ref: https://stackru.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, удалите аннотации типов из определения функции.
Скриншоты ограничены окном просмотра, но вы можете обойти это, захватив body
элемент, так как веб-драйвер будет захватывать весь элемент, даже если он больше, чем область просмотра. Это избавит вас от необходимости прокрутки и сшивания изображений, однако вы можете столкнуться с проблемами с положением нижнего колонтитула (как на скриншоте ниже).
Протестировано на Windows 8 с Chrome Driver.
url = "https://stackru.com/"
driver = webdriver.Chrome()
driver.get(url)
el = driver.find_element_by_tag_name('body')
el.screenshot('/path/to/save/in/scrape.png')
driver.quit()
Возвращает: (полный размер: )
Как это работает: установите максимальную высоту браузера...
#coding=utf-8
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def test_fullpage_screenshot(self):
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)
#the element with longest height on page
ele=driver.find_element("xpath", '//div[@class="react-grid-layout layout"]')
total_height = ele.size["height"]+1000
driver.set_window_size(1920, total_height) #the trick
time.sleep(2)
driver.save_screenshot("screenshot1.png")
driver.quit()
if __name__ == "__main__":
test_fullpage_screenshot()
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
Ключ в том, чтобы включить 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
отключен, сохраненный снимок экрана имеет примерно правильную ширину и высоту, но результат зависит от конкретного случая. Обычно сохраняется верхняя часть страницы, которая видна на экране, но остальная часть изображения просто белая. Также был случай с попыткой сохранить эту ветку переполнения стека с помощью указанной выше ссылки; не сохранилась даже верхняя часть, которая, что интересно, теперь была прозрачной, а остальная часть оставалась белой. Последний случай, который я заметил, был только один раз с данной ссылкой W3Schools; там, где нет белых частей, но верхняя часть страницы повторяется до конца, включая заголовок.
Я надеюсь, что это поможет многим из тех, кто по какой-то причине не получает ожидаемого результата, так как я не видел, чтобы кто-то явно объяснял требованиеheadless
mode с этим простым подходом. Только когда я сам обнаружил решение этой проблемы, я нашел сообщение от @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
.
Узнав подход @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")
Не уверен, что люди все еще имеют эту проблему. Я сделал небольшой хак, который работает довольно хорошо и хорошо сочетается с динамическими зонами. Надеюсь, поможет
# 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)
Почему бы просто не получить ширину и высоту страницы, а затем изменить размер драйвера? Так будет как то так
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")
Это сделает скриншот всей вашей страницы без необходимости объединять разные части.
Источник: 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.close()
driver.quit()
Я изменил код для 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')
Полные снимки экрана не являются частью спецификации W3C . Однако многие веб-драйверы реализуют свои собственные конечные точки, чтобы получить настоящий снимок экрана полной страницы. Я обнаружил, что этот метод с использованием 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 (Firefox)
Если вы используете 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 реализовал свою собственную функциональность полного снимка экрана:
https://chromium-review.googlesource.com/c/chromium/src/+/2300980
и команда Selenium, похоже, стремится к поддержке в Selenium 4:
Для 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"]))
Это работает как в режиме без головы, так и без него.
Мой первый ответ на Stackru. Я новичок. Другие ответы, процитированные коллегами-кодировщиками, потрясающие, и я даже не участвую в конкурсе. Я просто хотел бы процитировать шаги, предпринятые по следующей ссылке: 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()
Для Python с использованием Selenium 4 и драйвера Chrome
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()
Немного измените код @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')
Я изменил ответ, данный @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")
Если вы пытаетесь сделать этот пост ~ 2021, вам нужно отредактировать команду поиска элемента из:
element = driver.find_element_by_tag('body')
к:
from selenium.webdriver.common.by import By
...
element = driver.find_element(By.TAG_NAME, "body")
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.
Вы можете использовать Splinter
Splinter - это уровень абстракции поверх существующих инструментов автоматизации браузера, таких как Selenium
Есть новая функция browser.screenshot(..., full=True)
в новой версии 0.10.0
,full=True
опция сделает полный захват экрана для вас.
Легко на питоне, но медленно
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
Сейчас я использую такой подход:
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
Понял!!! работает как шарм
Для 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();
Это работает для меня
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
Я изменил ответ 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()