Here's a workaround. NB This script requires PIL (Python Imaging Library). If you're running PY 3.x, you'll need to have Python 2.7 installed alongside it.
In this demonstration, the method is contained in a file called util.py, which is imported by test.py. All scripts and created images live in the same directory. Obviously, you can adjust format, quality of image etc.
test.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | """ 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" self.driver.get(url) util.fullpage_screenshot(self.driver, "test.png") if __name__ == "__main__": unittest.main(argv=[sys.argv[0]]) |
util.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 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 |
Credits
The script used in util.py is essentially a shortened version of the one you will find here. Many thanks to restrada for coming up with it.
Hi This works great... but only one limitation though if the page has fixed headers... it has issues... e.g. this page here...
ReplyDeletehttp://www.w3schools.com/js/default.asp
Anyway to avoid the repeated headers... and also missing part of the page overlap.
I am getting error for
ReplyDeletefrom PIL import Image
Please help how to fix that
I found this!
Deletehttps://pillow.readthedocs.io/en/5.1.x/
Hi
ReplyDeleteThis code is working fine on Windows but for Mac my screenshot get cropped from right and bottom.
Your help is really appreciated.
Thanks
I know this is an old post, but I was having some trouble while using it on some sites because some boxes overlayed each other, all I did to solve it was using the next line as the first instruction of the function:
ReplyDeletedriver.execute_script("window.scrollTo(0, 0)")