asheets
asheets

Reputation: 870

Screenshot an element with python selenium shows image of wrong section of screen

I'm attempting to take a screenshot of a specific element on a webpage using the code in the answer to this question. This initially worked when I tested it a few days ago, but now the area it yields is consistently up and to the left of the target element.

The output of the original code isn't very helpful in debugging, so I've altered it to draw a rectangle around the area instead of cropping it.

Example:

from selenium import webdriver
from PIL import Image, ImageDraw
from io import BytesIO

browser = webdriver.Chrome()
browser.get('http://www.google.com')

logo = browser.find_element_by_id('hplogo') #id of 'Google' image

location = logo.location
size = logo.size

im = Image.open(BytesIO(browser.get_screenshot_as_png()))

draw = ImageDraw.Draw(im)
draw.rectangle(((location['x'], location['y']), (location['x'] + size['width'], location['y'] + size['height'])), outline='black')

im.show()
browser.quit()

Result: enter image description here

The box drawn seems to be in the right aspect ratio, but incorrect location and size. I would appreciate any explanation for what's causing this issue and any help with fixing it.

Upvotes: 5

Views: 2303

Answers (1)

asheets
asheets

Reputation: 870

The issue is pointed out in the comments to the accepted answer of the linked question: the size of the image returned by browser.get_screenshot_as_png() does not correspond to the actual window size. The image needs to be resized so that coordinates of the image correspond to the coordinates on the webpage.

Working code:

from selenium import webdriver
from PIL import Image, ImageDraw
from io import BytesIO

browser = webdriver.Chrome()
browser.get('http://www.google.com')

element = browser.find_element_by_id('hplogoy')
screen = browser.get_screenshot_as_png()

location = element.location
size = element.size

im = Image.open(BytesIO(screen)) # uses PIL library to open image in memory

screensize = (browser.execute_script("return document.body.clientWidth"), #Get size of the part of the screen visible in the screenshot
              browser.execute_script("return window.innerHeight"))
im = im.resize(screensize) #resize so coordinates in png correspond to coordinates on webpage

left = location['x']
top = location['y']
right = (location['x'] + size['width'])
bottom = (location['y'] + size['height'])

draw = ImageDraw.Draw(im)
draw.rectangle( ((left, top), (right, bottom)), outline='red')

browser.quit()
im.show()

Upvotes: 4

Related Questions