Python Selenium Power BI ScreenShot

Furkan Yusuf Pek
ÇSTech
Published in
5 min readMar 24, 2023
Python Selenium Power BI

From time to time, every data pipeline needs to be checked and if something is wrong, there must be alerting mechanism to make sure report stakeholders to see the right data. Also, these checks are important for data reliability.

My motto is if I am gonna repeat something more than three times, I try to automate it.

From that motto, I came up with the idea of Power BI selenium screenshots for daily report checks.

Python selenium is a powerful library that enables you to grab a screenshot of any web page. Also, you can mimic users’ behaviors like clicking buttons, filling out forms, etc. With that capabilities, I decided to automate our daily report checks with python selenium.

The main challenge here is when you try to grab a screenshot of a report, you need to log in to the Power BI portal using your credentials. You can’t simply get a screenshot of a page.

There are several things to make a screenshot of a Power BI report using selenium. First, we need to navigate to the login page for Power BI.

PowerBI Login Page

When we navigate to app.powerbi.com we need to fill in our email account. With selenium’s user mimic capabilities, we can fill that form. After filling email we need to hit submit button and selenium can do this for us.

# powerbi login url
driver.get('https://app.powerbi.com/?noSignUpCheck=1')
# wait for page load
time.sleep(2)
# find email area using xpath
email = driver.find_element_by_xpath('//*[@id="i0116"]')
# send power bi login user
email.send_keys(pbi_user)
# find submit button
submit = driver.find_element_by_id('idSIButton9')
# click for submit button
submit.click()
time.sleep(1)

Then, we need to fill in our password to the second form and hit to submit button.

# now we need to find password field
password = driver.find_element_by_id('i0118')
# then we send our user's password
password.send_keys(pbi_pass)
# after we find sign in button above
submit = driver.find_element_by_id('idSIButton9')
# then we click to submit button
submit.click()
time.sleep(1)

After these prompts, there is a third screen that asks you to stay signed in, we need to hit no for this.

# to complate the login process we need to click no button from above
# find no button by element
no = driver.find_element_by_id('idBtn_Back')
# then we click to no
no.click()
time.sleep(1)

After all these steps above, we now can navigate to our report using power bi links and grab a screenshot of our report.

ss_path = os.path.join(current_dir, "pbi_ss", ss_name)

report_url = ""

# Navigate to the report URL
driver.get(report_url)
# wait for report load
time.sleep(12)
# Take a screenshot of the report and save it to a file
driver.save_screenshot(ss_path)

Now we got our screenshot, we need to get rid of the unnecessary parts of it. So we find the report area of the screen with selenium and retrieve the height and width. After that, we crop the image and only the report area’s screenshot remains.

xpath_report_area = '//*[@id="pvExplorationHost"]/div/div/exploration/div/explore-canvas/div/div[2]/div/div[2]/div[2]'

# identifying the element to capture the screenshot
ss = driver.find_element_by_xpath(xpath_report_area)
# to get the element location
location = ss.location
# to get the dimension the element
size = ss.size

# to get the x axis
x = location['x']
# to get the y axis
y = location['y']
# to get the length the element
height = location['y'] + size['height']
# to get the width the element
width = location['x'] + size['width']

# to open the captured image
imgOpen = Image.open(ss_path)
# to crop the captured image to size of that element
imgOpen = imgOpen.crop((int(x), int(y), int(width), 2000))
cropped_image_ss = f"{ss_name}_cropped.png"
cropped_image_path = os.path.join(current_dir, "pbi_ss", cropped_image_ss)
# to save the cropped image
imgOpen.save(cropped_image_path)

With that screenshot, we can do anything that we want. We send it to a specific slack channel with custom text for our daily report checks.

Here is a full code for that operation;

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from PIL import Image
import time

# Set up the headless browser
options = Options()
options.headless = True
options.add_argument("--start-maximized")
driver = webdriver.Chrome(options=options) # replace with Firefox() if using Firefox

driver.set_window_size(3840, 2160) # optional

# Log in to Power BI

driver.get('https://app.powerbi.com/?noSignUpCheck=1')
time.sleep(2)
email = driver.find_element_by_xpath('//*[@id="i0116"]')
email.send_keys(pbi_user)

submit = driver.find_element_by_id('idSIButton9')
submit.click()
time.sleep(1)

password = driver.find_element_by_id('i0118')
password.send_keys(pbi_pass)

submit = driver.find_element_by_id('idSIButton9')
submit.click()
time.sleep(1)

no = driver.find_element_by_id('idBtn_Back')
no.click()
time.sleep(1)

print("Logged in successfully")

ss_path = os.path.join(current_dir, "pbi_ss", ss_name)

# set to powerbi report url
report_url = ""

# Navigate to the report URL
driver.get(report_url)
# wait for report load
time.sleep(12)
# Take a screenshot of the report and save it to a file
driver.save_screenshot(ss_path)

xpath_report_area = '//*[@id="pvExplorationHost"]/div/div/exploration/div/explore-canvas/div/div[2]/div/div[2]/div[2]'

# identifying the element to capture the screenshot
ss = driver.find_element_by_xpath(xpath_report_area)
# to get the element location
location = ss.location
# to get the dimension the element
size = ss.size

# to get the x axis
x = location['x']
# to get the y axis
y = location['y']
# to get the length the element
height = location['y'] + size['height']
# to get the width the element
width = location['x'] + size['width']

# to open the captured image
imgOpen = Image.open(ss_path)
# to crop the captured image to size of that element
imgOpen = imgOpen.crop((int(x), int(y), int(width), 2000))
cropped_image_ss = f"{ss_name}_cropped.png"
cropped_image_path = os.path.join(current_dir, "pbi_ss", cropped_image_ss)
# to save the cropped image
imgOpen.save(cropped_image_path)

Thanks for reading and for your time, you can always reach me via LinkedIn. 👋

--

--