Taking a whole page screenshot with Selenium Marionette in Python

Stef Verdonk picture Stef Verdonk · Jun 19, 2016 · Viewed 11.3k times · Source

After the recent Firefox upgrade to version 47 we were forced to install the Marionette extension to keep being able to use selenium webdriver, and in my case also upgrade selenium from 2.52 to 2.53.

I use the python version of selenium webdriver to acquire high resolution images of maps rendered in HTML and JavaScript. previously this worked fine in firefox and the screenshots could be taken of the whole page, far beyond the dimensions of my own screen. However with the recent changes the screenshot is taken only of the area visible on screen. I use the following code:

import time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

caps = DesiredCapabilities.FIREFOX
caps["marionette"] = True

browser = webdriver.Firefox(capabilities=caps)
browser.get(html_file)
time.sleep(15)

browser.save_screenshot(image_name)
browser.quit()

I have already considered: downgrading, stitching together several screenshots or switching to Qgis. However I would prefer a more elegant solution which would allow me to keep using the latest version of firefox and roughly the same methodology. Does anyone know a solution to this? perhaps by tricking selenium in thinking the viewport is larger? or by using another linux supported browser which does allow for the full page screenshot?

Answer

Martin Krung picture Martin Krung · Mar 1, 2017

This is what I use, just stitch it:

#!/usr/bin/python
from selenium import webdriver
from PIL import Image
from cStringIO import StringIO

verbose = 1

browser = webdriver.Firefox()
browser.get('http://stackoverflow.com/questions/37906704/taking-a-whole-page-screenshot-with-selenium-marionette-in-python')

# from here http://stackoverflow.com/questions/1145850/how-to-get-height-of-entire-document-with-javascript
js = 'return Math.max( document.body.scrollHeight, document.body.offsetHeight,  document.documentElement.clientHeight,  document.documentElement.scrollHeight,  document.documentElement.offsetHeight);'

scrollheight = browser.execute_script(js)

if verbose > 0: 
    print scrollheight

slices = []
offset = 0
while offset < scrollheight:
    if verbose > 0: 
        print offset

    browser.execute_script("window.scrollTo(0, %s);" % offset)
    img = Image.open(StringIO(browser.get_screenshot_as_png()))
    offset += img.size[1]
    slices.append(img)

    if verbose > 0:
        browser.get_screenshot_as_file('%s/screen_%s.png' % ('/tmp', offset))
        print scrollheight


screenshot = Image.new('RGB', (slices[0].size[0], scrollheight))
offset = 0
for img in slices:
    screenshot.paste(img, (0, offset))
    offset += img.size[1]

screenshot.save('/tmp/test.png')

code also here: https://gist.github.com/fabtho/13e4a2e7cfbfde671b8fa81bbe9359fb

Problem with scrolling/stich are, that html nodes set to "display: fixed" keep repeating on every shot you do.