How to accept cookies popup within #shadow-root (open) using Selenium Python - python

I am trying to press the accept button in a cookies popup in the website https://www.immobilienscout24.de/
Snapshot:
I understand that this requires
driver.execute_script("""return document.querySelector('#usercentrics-root')""")
But I can't trickle down the path to the accept button in order to click it. Can anyone provide some help?

This is one way (tested & working) you can click that button: please observe the imports, as well as the code after defining the browser/driver:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
chrome_options = Options()
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument('disable-notifications')
import time as t
webdriver_service = Service("chromedriver/chromedriver") ## path to where you saved chromedriver binary
browser = webdriver.Chrome(service=webdriver_service, options=chrome_options)
actions = ActionChains(browser)
url = 'https://www.immobilienscout24.at/regional/wien/wien/wohnung-kaufen'
browser.get(url)
page_title = WebDriverWait(browser, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, "a[title='Zur Homepage']")))
actions.move_to_element(page_title).perform()
parent_div = WebDriverWait(browser, 20000).until(EC.presence_of_element_located((By.ID, "usercentrics-root")))
shadowRoot = browser.execute_script("return arguments[0].shadowRoot", parent_div)
try:
button = WebDriverWait(shadowRoot, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-testid='uc-accept-all-button']")))
button.click()
print('clicked')
except Exception as e:
print(e)
print('no click button')
That page is reacting to user's behavior, and it will only fully load the page once it detects mouse movements, hence the ActionChains() part of the code. After that, we drill down into the shadow root element, we locate the button (using Waits, to make sure it's clickable), and then we click it.
Selenium documentation can be found at https://www.selenium.dev/documentation/

The element Alle akzeptieren within the website is located within a #shadow-root (open).
Solution
To click on the element Alle akzeptieren you have to use shadowRoot.querySelector() and you can use the following Locator Strategy:
Code Block:
driver.execute("get", {'url': 'https://www.immobilienscout24.de/'})
time.sleep(10)
item = driver.execute_script('''return document.querySelector('div#usercentrics-root').shadowRoot.querySelector('button[data-testid="uc-accept-all-button"]')''')
item.click()

Related

Click button with Selenium Python works only with debug mode

I tried to get data from the menu in this website. I've written this script which seems work well in debug mode. In this script, i close the chrome every time I've get information for certain city.
In debug mode, the detail information is shown when 'element' is clicked by the script. However, if i run the script, it seems that it doesn't do anything after city information is sent. The button 'Visualize Results' is enabled in the website when city data is entered, but the detail information that supposed to be shown after clicking this button by the script is not shown as if it is not clicked. Is there something that i miss?
thank you in advance.
for city in Cities:
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get(link)
driver.find_element(By.ID, "inputText").send_keys(city)
driver.find_element(By.ID, 'btninputText').click()
element = wait(driver, 5).until(EC.presence_of_element_located((By.XPATH,div[#id="btviewPVGridGraph"]'))).click()
driver.close()
You need to wait for clickability of all 3 elements you accessing here. Presence is not enough.
Need to add a short delay between clicking the search button and clicking visualization button
The following code works:
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument("start-maximized")
webdriver_service = Service('C:\webdrivers\chromedriver.exe')
driver = webdriver.Chrome(options=options, service=webdriver_service)
wait = WebDriverWait(driver, 30)
url = "https://re.jrc.ec.europa.eu/pvg_tools/en/"
driver.get(url)
wait.until(EC.element_to_be_clickable((By.ID, "inputText"))).send_keys("Paris")
wait.until(EC.element_to_be_clickable((By.ID, "btninputText"))).click()
time.sleep(2)
wait.until(EC.element_to_be_clickable((By.ID, "btviewPVGridGraph"))).click()
Th result is:
Try below xpath
wait(driver, 5).until(EC.presence_of_element_located(By.XPATH,'//div[#id="btviewPVGridGraph"]')).click()

Unable to click button - Python / Selenium & bs4

Im trying to click a button and tried already several different methods with no avail.
Method 1:
WebDriverWait(driver, 20).until(EC.invisibility_of_element((By.CLASS_NAME, 'sc-gsDKAQ fWOgSr')))
driver.execute_script("arguments[0].click();", WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CLASS_NAME, 'sc-gsDKAQ fWOgSr'))))
Method 2:
driver.find_element(by=By.CLASS_NAME, value='sc-gsDKAQ fWOgSr').click()
Method 3:
btn = driver.find_element(by=By.CLASS_NAME, value='sc-gsDKAQ fWOgSr')
btn.click()
Error messages:
M1: Timeout
M2: NoSuchElementException
M3: NoSuchElementException
I tried the same by looking with Xpath, no success. Had another Error in the past, which stated that "String" cannot be interacted with.
That element is in a #shadow root element, so it's a bit fiddly to reach. Also, page seems to react at mouse movements (and only load after it detect some mouse movement). The following code seems to work: setup is on Linux, but you can adapt it to your own, just observe the imports and the part after defining the browser:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
chrome_options = Options()
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument('disable-notifications')
import time as t
webdriver_service = Service("chromedriver/chromedriver") ## path to where you saved chromedriver binary
browser = webdriver.Chrome(service=webdriver_service, options=chrome_options)
actions = ActionChains(browser)
url = 'https://www.immobilienscout24.at/regional/wien/wien/wohnung-kaufen'
browser.get(url)
page_title = WebDriverWait(browser, 3).until(EC.presence_of_element_located((By.CSS_SELECTOR, "a[title='Zur Homepage']")))
actions.move_to_element(page_title).perform()
parent_div = WebDriverWait(browser, 20000).until(EC.presence_of_element_located((By.ID, "usercentrics-root")))
shadowRoot = browser.execute_script("return arguments[0].shadowRoot", parent_div)
try:
button = WebDriverWait(shadowRoot, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-testid='uc-accept-all-button']")))
button.click()
print('clicked')
except Exception as e:
print(e)
print('no click button')
This will click the button, and print in the terminal:
clicked

How to access the iframe using Selenium and Python on Glassdoor

I am trying to automate application process on Glassdoor using the EasyApply button. Now after identifying the EasyApply Button and successfully clicking it, I need to switch to the Frame so as to access the HTML content of the form to be able to send in my form details.
I used:
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "#indeedapply-modal-preload-1658752913396-iframe")))
to perform the switching but still could not access the frame's html content.
Here is the block that performs this operation:
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
#if it has easy-apply, then perform application
if len(driver.find_elements_by_xpath('//*[#id="JDCol"]/div/article/div/div[1]/div/div/div[1]/div[3]/div[2]/div/div[1]/div[1]/button')) > 0:
driver.find_element_by_xpath('//*[#id="JDCol"]/div/article/div/div[1]/div/div/div[1]/div[3]/div[2]/div/div[1]/div[1]/button').click()
wait = WebDriverWait(driver, 50)
time.sleep(5)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "#indeedapply-modal-preload-1658752913396-iframe")))
name = driver.find_element(By.CSS_SELECTOR, '#input-applicant.name')
name.send_keys('Oluyele Anthony')
elif len(driver.find_elements_by_xpath('//*[#id="JDCol"]/div/article/div/div[1]/div/div/div[1]/div[3]/div[2]/div/div[1]/div[1]/a')) > 0:
driver.find_element_by_xpath('//*[#id="JDCol"]/div/article/div/div[1]/div/div/div[1]/div[3]/div[2]/div/div[1]/div[1]/a').click()
Here is the HTML content for the frame
<iframe name="indeedapply-modal-preload-1659146630884-iframe" id="indeedapply-modal-preload-1659146630884-iframe" scrolling="no" frameborder="0" title="Job application form container" src="https://apply.indeed.com/indeedapply/xpc?v=5#%7B%22cn%22:%224AaHlXdnW4%22,%22ppu%22:%22https://www.glassdoor.com/robots.txt%22,%22lpu%22:%22https://apply.indeed.com/robots.txt%22,%22setupms%22:1659146630959,%22preload%22:true,%22iaUid%22:%221g96dgr7uii3h800%22,%22parentURL%22:%22https://www.glassdoor.com/Job/nigeria-data-science-jobs-SRCH_IL.0,7_IN177_KO8,20.htm?clickSource=searchBox%22%7D" style="border: 0px; vertical-align: bottom; width: 100%; height: 100%;"></iframe>
Apparently, after running the cell, the:
TimeoutException: Message:
Error occurs which shows that the frame is not being switched to.
The middle part of the value of id attribute i.e. 1658752913396 is dynamically generated and is bound to change sooner/later. They may change next time you access the application afresh or even while next application startup. So can't be used in locators.
Solution
To switch to the <iframe> you can use either of the following Locator Strategies:
Using id attribute:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[title='Job application form container'][id^='indeedapply-modal-preload']")))
Using XPATH:
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[title='Job application form container' and starts-with(#id, 'indeedapply-modal-preload')]")))
Using name attribute:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[title='Job application form container'][name^='indeedapply-modal-preload']")))
Using XPATH:
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[title='Job application form container' and starts-with(#name, 'indeedapply-modal-preload')]")))
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
There are 2 iframes in that page and the second iframe contains another (nested) iframe. The following code will sort out your problem (setup is for linux, but you can figure it out - pay attention to imports, and to the code after getting the url):
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time as t
chrome_options = Options()
chrome_options.add_argument("--no-sandbox")
webdriver_service = Service("chromedriver/chromedriver") ## path to where you saved chromedriver binary
browser = webdriver.Chrome(service=webdriver_service, options=chrome_options)
url = 'https://www.glassdoor.com/Job/nigeria-data-science-jobs-SRCH_IL.0,7_IN177_KO8,20.htm?clickSource=searchBox'
browser.get(url)
button = WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, '//button[#data-test="applyButton"]')))
button.click()
iframes = WebDriverWait(browser, 20).until(EC.presence_of_all_elements_located((By.TAG_NAME, "iframe")))
print(len(iframes))
for iframe in iframes:
print(iframe.get_attribute('id'))
browser.switch_to.frame(iframes[1])
t.sleep(2)
WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//*[#title='Job application form']")))
t.sleep(2)
applicant_name = WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.ID, 'input-applicant.name')))
applicant_name.click()
applicant_name.send_keys('hello dolly')
Let me know if it works for you.
UPDATE: It appears that website changed its structure since yesterday, and now there are 11/13 iframes per page. Also, if the job selected from the main column does not offer Easy Apply, you get an error. The updated code (below) is selecting the Easy Apply jobs from page, goes through each of them, clicks easyapply button, select the correct iframe/nested iframe, and does stuff to that form. It currently works, until that website will change its format again:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time as t
chrome_options = Options()
chrome_options.add_argument("--no-sandbox")
webdriver_service = Service("chromedriver/chromedriver") ## path to where you saved chromedriver binary
browser = webdriver.Chrome(service=webdriver_service, options=chrome_options)
url = 'https://www.glassdoor.com/Job/nigeria-data-science-jobs-SRCH_IL.0,7_IN177_KO8,20.htm?clickSource=searchBox'
browser.get(url)
jobs = WebDriverWait(browser, 20).until(EC.presence_of_all_elements_located((By.XPATH, "//li[#data-is-easy-apply='true']")))
while True:
for job in jobs:
try:
print(job.text)
job.click()
try:
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[#alt='Close']"))).click()
except Exception as e:
print('no request to login')
t.sleep(2)
button = WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, '//button[#data-test="applyButton"]')))
button.click()
WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//*[#title='Job application form container']")))
t.sleep(2)
WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//*[#title='Job application form']")))
t.sleep(2)
applicant_name = WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.ID, 'input-applicant.name')))
applicant_name.click()
applicant_name.send_keys('hello dolly')
t.sleep(2)
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[#id='form-action-cancel']"))).click()
t.sleep(2)
browser.switch_to.default_content()
t.sleep(2)
except Exception as e:
print(e)
break

python selenium - Cant find the element of sign in button

I'm trying to create an automation test in Asos (for practice purpose only) however I'm having a hard time locating this sign-in element...
I need to click on that sign-in button.
these are the element I got in inspect:
a class="_1336dMe _1uUU2Co _1336dMe _1uUU2Co" href="https://my.asos.com/my-account?
lang=en-GB&store=COM&country=GB&keyStoreDataversion=3pmn72e-27"
data-testid="signin-link" tabindex="-1">Sign In
I had the same problem when trying to find this button on Google Maps. Is the sign in button on a pop up window? Then the problem is becuse you have to change between frames.
Here is a code sample:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome('driver path')
url = 'url'
driver.get(url)
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, '//*[#id="consent-bump"]/div/div[1]/iframe')))
agree = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="introAgreeButton"]/span/span')))
agree.click()
#back to the main page
driver.switch_to_default_content()
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="searchboxinput"]'))).send_keys('gostilne')
search = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="searchbox-searchbutton"]')))
search.click()
Make shure that the xpath for frames and buttons is correct.

Can't click on a button using Selenium (web scrape)

I am trying to click on this button so that I can proceed to the next page but doesn't seem to be working for me. I am trying to click on the 'Search for an inspection report' button.
This is the xpath for this source. //[#id="btnOK"] . And so I was trying to use driver.find_element_by_xpath('//[#id="btnOK"]').click() and it gives me an error saying unable to locate element.
Here is the link to the site.
https://www.halton.ca/For-Residents/Food-Safety/Dinewise/Search-Directory-of-Food-Premises-Dinewise
Any help would be great.
It is because the button is present within a different iframe. In order to click that button, u have to switch focus to that iframe. This is how u do it:
iframe = driver.find_element_by_id("iframe-form")
driver.switch_to.frame(iframe)
btn = driver.find_element_by_xpath('//*[#id="btnOK"]')
btn.click()
Plus, another thing to note is that the xpath u have provided is wrong. U have missed a * in the xpath. The right xpath is '//*[#id="btnOK"]'.
Complete code:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.halton.ca/For-Residents/Food-Safety/Dinewise/Search-Directory-of-Food-Premises-Dinewise')
iframe = driver.find_element_by_id("iframe-form")
driver.switch_to.frame(iframe)
btn = driver.find_element_by_xpath('//*[#id="btnOK"]')
btn.click()
Hope that this helps.
Alternative solution using webdriver wait:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
#chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
wd = webdriver.Chrome('<PATH_TO_CHROMEDRIVER>', options=chrome_options)
# load page via selenium
wd.get("https://www.halton.ca/For-Residents/Food-Safety/Dinewise/Search-Directory-of-Food-Premises-Dinewise")
# wait for iframe, switch to it
frame = WebDriverWait(wd, 30).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"iframe-form")))
# wait for button, scroll to it, click it
btn = WebDriverWait(wd, 30).until(EC.presence_of_element_located((By.ID, 'btnOK')))
wd.execute_script("arguments[0].scrollIntoView();", btn)
wd.execute_script("arguments[0].click();", btn)

Categories

Resources