Сделайте скриншот полной страницы с помощью 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; там, где нет белых частей, но верхняя часть страницы повторяется до конца, включая заголовок.

Я надеюсь, что это поможет многим из тех, кто по какой-то причине не получает ожидаемого результата, так как я не видел, чтобы кто-то явно объяснял требованиеheadlessmode с этим простым подходом. Только когда я сам обнаружил решение этой проблемы, я нашел сообщение от @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:

https://github.com/SeleniumHQ/selenium/issues/8168

Для 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()
Другие вопросы по тегам