Clicking Side Panel Elements in Selenium Without IFrames

2024/10/11 12:24:06

I want to download U.S. Department of Housing and Urban Development data using Python's Selenium. Here's my code.

import os
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Selectoptions = webdriver.ChromeOptions()
preferences= {"download.default_directory": os.getcwd(), "directory_upgrade": True}
options.add_experimental_option("prefs", preferences)
#options.headless = True
options.add_experimental_option('excludeSwitches', ['enable-logging'])url = "https://hudgis-hud.opendata.arcgis.com/datasets/deteriorated-paint-index-by-county/explore"# Path of my WebDriver
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)wait = WebDriverWait(driver, 60)# to maximize the browser window
driver.maximize_window()#get method to launch the URL
driver.get(url)paths = ["#ember97", "calcite-card > div > calcite-button"]for x in paths:wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, x))).click()

I can click the button to expand the side panel, where the CSV file button is located, but I cannot click the CSV file itself to download it. My first thought was to check for if the side panel existed within an IFRAME, so I did

seq = driver.find_elements_by_tag_name('iframe')
seq

And it returned nothing. The content is nested in a class called side-panel-ref. Is there a way to switch to this somehow so I can click that content, when iframes aren't there? What might I be missing?

Answer

Your button is inside a shadowroot.

You see this when you inspect in devtools:

devtools shadowroot

Quickest and easiest way to handle this is with some JS .This is your script slightly refactored + the JS call:

url = "https://hudgis-hud.opendata.arcgis.com/datasets/deteriorated-paint-index-by-county/explore"
wait = WebDriverWait(driver, 60)
driver.maximize_window()
driver.get(url)wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#ember97'))).click()
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.dataset-download-card > hub-download-card")))driver.execute_script('document.querySelector("div.dataset-download-card > hub-download-card").shadowRoot.querySelector("calcite-card > div > calcite-button").click()')

It's a fairly lengthy JS call. It's reasonably self explanatory if you read it, there are 5 parts to it: document.querySelector(..).shadowRoot.querySelector(..).click() - but just ask if you need more support.

Please also be aware that selenium is bad at downloading files. There's no API that exposes the downloads progress. You'll need to ensure your browser remains open while you download the file.

It seems a pretty quick download so you might get away with a hard coded sleep.

Also worth a mention - If you're not a fan of the long JS, you can also break it down like so:

container = driver.find_element_by_css_selector("div.dataset-download-card > hub-download-card")
shadowRoot = driver.execute_script("return arguments[0].shadowRoot", container)
shadowRoot.find_element_by_css_selector("calcite-card > div > calcite-button").click()
https://en.xdnf.cn/q/118329.html

Related Q&A

Library to extract data from open Excel workbooks

I am trying to extract data from workbooks that are already open. I have found the xlrd library, but it appears you can only use this with workbooks you open through Python. The workbooks I will use in…

Keras apply different Dense layer to each timestep

I have training data in the shape of (-1, 10) and I want to apply a different Dense layer to each timestep. Currently, I tried to achieve this by reshaping input to (-1, 20, 1) and then using a TimeDis…

Create a pass-through for an installed module to achieve an optional import

Im writing a library in python 3.7. Id like it to have as few dependencies as possible. For example, tqdm is nice to have but ideally Id like my library to work without it if its not there. Therefore, …

Django, Redis: Where to put connection-code

I have to query redis on every request in my Django-app. Where can I put the setup/ connection routine (r = redis.Redis(host=localhost, port=6379)) so that I can access and reuse the connection without…

Events and Bindings in tkinter does not work in loop

I am trying to create binding in a loop using tkinter module.from tkinter import * class Gui(Frame):def __init__(self, parent):Frame.__init__(self, parent) self.parent = parentself.initUI()def Arrays(…

Python Machine Learning Algorithm to Recognize Known Events

I have two sets of data. These data are logged voltages of two points A and B in a circuit. Voltage A is the main component of the circuit, and B is a sub-circuit. Every positive voltage in B is (1) co…

How can I replace Unicode characters in Python?

Im pulling Twitter data via their API and one of the tweets has a special character (the right apostrophe) and I keep getting an error saying that Python cant map or character map the character. Ive lo…

Filtering Pandas DataFrame using a condition on column values that are numpy arrays

I have a Pandas DataFrame called dt, which has two columns called A and B. The values of column B are numpy arrays; Something like this: index A B 0 a [1,2,3] 1 b [2,3,4] 2 c …

Creation a tridiagonal block matrix in python [duplicate]

This question already has answers here:Block tridiagonal matrix python(9 answers)Closed 6 years ago.How can I create this matrix using python ? Ive already created S , T , X ,W ,Y and Z as well as the…

Python tkinter checkbutton value always equal to 0

I put the checkbutton on the text widget, but everytime I select a checkbutton, the function checkbutton_value is called, and it returns 0.Part of the code is :def callback():file_name=askopenfilename(…