Selenium Python - Finding Elements by Class Name With dynamic parameters - python

I was wondering if there is any way to find element by class name if the class name have a static param and dynamic param, I'll explain:
I got
< class="**dataset-selection-dialog-actions** *ng-tns-c139-19*" >
the 'dataset-selection-dialog-actions' is static but 'ng-tns-c139-19' can be change of any reload page.
can I locate this element without the dynamic param ?
thanks.

yes why not.
Please use find_element_by_class_name('dataset-selection-dialog-actions')
but make sure that it is unique element in HTMLDOM.
to check if it is unique or not, use this css selector, .dataset-selection-dialog-actions
PS : Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the css selector .dataset-selection-dialog-actions and see, if your desired element is getting highlighted with 1/1 matching node.

Related

Selenium/Python Unable to use `:contains()` in CSS_SELECTOR [duplicate]

This question already has answers here:
selenium.common.exceptions.InvalidSelectorException with "span:contains('string')"
(2 answers)
Closed 1 year ago.
When I try to use :contains in Selenium's By.CSS_SELECTOR, such as
presence = EC.presence_of_element_located((By.CSS_SELECTOR, ".btn:contains('Continue Shopping')"))
or
presence = EC.presence_of_element_located((By.CSS_SELECTOR, ".btn\:contains('Continue Shopping')"))
or
presence = EC.presence_of_element_located((By.CSS_SELECTOR, ".btn\\:contains('Continue Shopping')"))
the Python program crashes with the error
Exception: Message: invalid selector: An invalid or illegal selector was specified
(Session info: chrome=95.0.4638.54)
Is it possible to use :contains in Selenium? The CSS selector
$('.btn:contains("Continue Shopping")')
works fine in Chrome's JS console.
Using Chrome 95.0.4638.54, ChromeDriver 95.0.4638.54, Python 3.10 on Ubuntu 20.04.
The selector :contains('text') is a jQuery selector, not a valid CSS selector like Selenium is expecting. I'm assuming the reason it works on the page via Chrome's DevTools console is because the page has jQuery defined on it.
Unfortunately, I do not believe you can directly select an element via its text using a CSS selector (link).
You have two options as far as I can see:
Alter your selector to be class or ID based (easiest)
Create a Selenium utility to run a JS script that uses this jQuery selector; e.g. execute_script("jQuery(" + id + ":contains('" + text + "')", id, text)
As mentioned by Aspok your CSS locators are not a valid CSS locators.
To locate element based on it text you can use XPath locator, something like:
//*[contains(#class,'btn') and(contains(text(),'Continue Shopping'))]
In case btn is the only class name attribute of that element your XPath can be
//*[#class='btn' and(contains(text(),'Continue Shopping'))]
As explained by #aspok, it is not a valid css selector.
In case you would like to have XPath for the same, and .btn is class and have text/partial text
Continue Shopping
You can try the below XPath :
//*[contains(text(),'Continue Shopping')]
or
//*[contains(text(), 'Continue Shopping') and contains(#class, 'btn')]
Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
xpath that you should check :
//*[contains(text(), 'Continue Shopping') and contains(#class, 'btn')]
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
Also, Just letting you know that, //* can be replaced by tag name, if you found multiple matching nodes.

Change css element style with Python Selenium

I want to change the css element style using Python Selenium while doing automation to increase the height of the page. The html of the element is as follows:
<div style="overflow-y:scroll;overflow-x:hidden;height:150px;">
I know that I can use something like the code below to do this:
driver.execute_script("document.getElementById('id name').style.height = '2000px';")
or
driver.execute_script("document.getElementByClassName('class name').style.height = '2000px';")
But there is no id or class in the HTML (there's only style).
If no ID or class is present then please use CSS
driver.execute_script("document.getElementByCss('div[style='overflow-y:scroll']').style.height = '2000px';")
But you should check in HTML DOM for the mentioned CSS :
Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the CSS and see, if your desired element is getting highlighted with 1/1 matching node.
CSS you should check :
div[style='overflow-y:scroll']
or
div[style='overflow-y:scroll'][sytle$='height:150px;']
or
div[style='overflow-y:scroll;overflow-x:hidden;height:150px;']
Whichever has the unique entry put that in execute_script and you should be good to go after that.
Alternate way to do
element = driver.find_element_by_css_selector("div[style='overflow-y:scroll;overflow-x:hidden;height:150px;']")
driver.execute_script("arguments[0].setAttribute('style','overflow-y:scroll;overflow-x:hidden;height:2000px;')", element)

How to get xpath which contains a variable

Im trying to get videos length using xPath but the aria-label changes on every video it looks like this //*[#aria-label="10 seconds"]
How can i specify this element path
here's the html source
<span id="text" class="style-scope ytd-thumbnail-overlay-time-status-renderer" aria-label="20 seconds"> 0:20 </span>
If this id is unique text
directly try to extract the .text or do a .get_attribute
Using .text :
video_len = driver.find_element_by_id('text').text
print(video_len)
Using .get_attribute() :
video_len = driver.find_element_by_id('text').get_attribute('aria-label')
print(video_len)
PS : Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
You can try the same two methods with the below css
span.style-scope.ytd-thumbnail-overlay-time-status-renderer
always check in HTMLDOM, if we have unique entry or not for any locator.

Element not found when using webdriver with Selenium in Python

got a problem with my code and I need your help. What I'm trying to do is the following:
1- access a website;
2- fill the registration form: name, email, password, etc.
Step 1 works; after clicking the sign up button, the form will pop up in a new tab.
Step 2; when trying to find the elements, by, id or name, I get the error "selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element"
My code is the following:
driver.find_element_by_link_text('Sign Up').click()
time.sleep(3)
driver.find_element_by_id("signup_title").send_keys(signup_tile)
driver.find_element_by_id("signup_name").send_keys(signup_name)
Attached you can find the html. Thank you in advance, much appreciated your help.
Note
In console I tried to find the element searching the id using
$x("//*[#id='signup_title']") and it was found: [input#signup_title.sc-AxirZ.kzqQJb.invalid]. Also the element is loaded.
HTML
Try using:
driver.find_element_by_xpath("<XPath>")
It seems to work better. To get the XPath of an element, find the element in the inspector, right-click it then Copy -> Copy XPath. If that doesn't work, select Copy Full XPath instead
The problem was related to the second tab; because the form opens in another tab, the window must be switched in the code.
I used the following:
driver.switch_to.window(driver.window_handles['Nr']), Nr being the index for the tab- if there are 2, the main one, and the second one-in my case with the form, the index will pe 1-counting starts from zero.

Unable to type into text field of Javascript form with Selenium / Python (element not interactable)

I'm using Selenium and coding with Python.
I'm trying to do the following: for a flight search website, under Flight 1's 'Enter routing code' text box, type 'AA'
This is the code that I have at the moment:
flight1_routing = driver.find_element_by_xpath(".//*[#id='ita_form_location_RouteLanguageTextBox_0']")
flight1_routing.clear()
flight1_origin.send_keys("AA")
But instead, I get this error message: "invalid element state: Element is not currently interactable and may not be manipulated". How can this be with a regular text field that is also not an autocomplete field, AFAIK?
if you get Element is not currently interactable check if the element is not disabled and its visible. if you want to hack it execute JS to enable it.
i visited the homepage id ita_form_location_RouteLanguageTextBox_0 doesnt exist also under flight one there's no Enter routing code. i can see the text box saying airport city or city name
Also if you have the id prefer to use find_element_by_id if not try to use css selector if you can rather than xpath. Its much cleaner.
Update
here's a working script:
As recomended above, the elements selected are not visible. what is actualy done, is that there's 5-6 different elements all hidden and when you click on show advanced route it picks 2 random ones and makes them visible.
So the id is not always the same. If you use the same id you will get a hidden element some times(because it picks random ids) so selenium is not able to deal with it. i made a selector that gets the 2 hidden elements
from selenium import webdriver
import selenium.webdriver.support.ui as ui
driver = webdriver.Firefox()
driver.get("http://matrix.itasoftware.com/")
#click on the multi tab
tab = driver.find_element_by_id("ita_layout_TabContainer_0_tablist_ita_form_multislice_MultiSliceForm_0").click()
#click on the advanced routes
advanced_routing=ui.WebDriverWait(driver, 10).until(
lambda driver : driver.find_element_by_id("sites_matrix_layout_RouteLanguageToggleLink_1")
)
advanced_routing.click()
#get all visible elements with id like ita_form_location_RouteLanguageTextBox. its similar to regex ita_form_location_RouteLanguageTextBox.*
element = ui.WebDriverWait(driver, 10).until(
lambda driver : driver.find_elements_by_css_selector("[id*=ita_form_multislice_MultiSliceRow] [id*=ita_form_location_RouteLanguageTextBox]")
)
element[0].send_keys("foo")
element[1].send_keys("bar")
import time
time.sleep(20)
Did you click into the correct tab first & enable advanced routing codes?? e.g.
#Go to right tab
driver.find_element_by_css_selector("div#ta_layout_TabContainer_0_tablist_ita_form_multislice_MultiSliceForm_0 > span").click()
#Enable routing
driver.find_element_by_css_selector("a.itaToggleLink").click()
#note I seem to get a different id to the one you're using, assuming its dynamic numbering so handling all cases
#if you know how the dynamic numbering works youmay be able to deduce a single id that will work for your test case
#Instead I'm going for finding all elements matching a pattern then searching through them, assuming only one will be visible
flight1_routings = driver.find_elements_by_css_selector("input[id^='ita_form_location_RouteLanguageTextBox_']")
#probably better finding it then using it separately, but I was feeling lazy sorry.
for route in flight1_routings:
if route.is_displayed():
route.clear()
route.send_keys("AA")
Also you can probably skip the .clear() call as it looks like the box starts with no text to overwrite.
Edit: Updated the enable routing toggling to handle not knowing the id, the class name stays the same, should work. Handling finding the input despite variable id as suggested by foo bar with the css selector, just then iterating over that list and checking if its on top

Categories

Resources