I have been using selenium for a little bit now and have been stuck on this issue for the past few hours. It seems really simple but I just can't seem to figure out a proper execution. I basically am trying to select a shoe size based on the user's input. Here are a few of the buttons I am trying to sort through as well as the surrounding HTML.
<p class="checkbox-size">
<input type="radio" value="500" id="super_attribute[150]_500" name="super_attribute[150]" class="product_attribute">
<label for="super_attribute[150]_500">
<span id="label_eu0" class="label_hidden"> 38.5</span>
<span id="label_us0" class="label_show"> 6</span>
<span id="label_uk0" class="label_hidden"> 5.5</span>
<span id="label_cm0" class="label_hidden"> 24</span>
</label>
</p>
The specific button I am trying to press is this one:
<label for="super_attribute[150]_137">
<span id="label_eu10" class="label_hidden"> 45</span>
<span id="label_us10" class="label_show"> 11</span>
<span id="label_uk10" class="label_hidden"> 10</span>
<span id="label_cm10" class="label_hidden"> 29</span>
</label>
Now I tried many different methods of searching then clicking one of the buttons but nothing has worked yet. Any suggestions? Here is what I am currently using to try and find and click the button:
driver.find_element_by_css_selector("input[type='radio'][value='11']").click()
Looking back I might have not provided the correct code for the buttons, so here is a snapshot of the inspect element as well as the actual page if you want to go check it out for yourself. I am trying to click the size buttons. Button inspect element
Solved!
Here is the code I ended up using.
sizes = driver.find_elements_by_class_name('checkbox-size')
for size in sizes:
if size.text in [usersize]:
size.click()
print colored('Carted size %s'%(size.text), 'green')
break
continue
There are a few problems with your approach.
You are trying to click the INPUT when you need to click a SPAN
The sizes on the page contain some amount of whitespace which makes your strict string comparison, value='11', not work. Also the contained text is not considered a value.
Another issue you will run into is that all of the sizes aren't displayed. The sizes displayed is controlled by the links above the sizes, EU, US, UK, and CM. The ones that are displayed have class="label_show" so you will want to specify that in your answer or you will attempt to click elements that are not visible which will throw an exception. (Selenium only interacts with visible elements by design).
With all this, we can build the following XPath
//span[#class='label_show'][normalize-space(.)='10']
If it were me, I would throw this in a function that pass in the desired size as a string and insert that parameter into the above XPath to make this much more reusable.
Try the below locator(xpath):
.//span[contains(#id,'label_eu') and text()=' 40']
Ok so here is what I ended up using which solved the issue. I made a list of all the web elements with the class 'checkbox-size' then traversed that list to to find the correct size, and then click on that element.
Here is the code:
sizes = driver.find_elements_by_class_name('checkbox-size')
for size in sizes:
if size.text in [usersize]:
size.click()
print colored('Carted size %s'%(size.text), 'green')
break
continue
Related
After third attempt of solving this problem, I am unable to finalize this on my own. I would appreciate, if someone would like to share their thoughts on the following issue.
Let us assume, we have such kind of HTML structure:
<div class="panel"></div>
<div class="title"></div>
<h3 class="title">HEADER NUMBER ONE<h3>
<div class="area"></div>
<div class="something">IO field</div>
<input class="input"></input>
<div class="panel"></div>
<div class="title"></div>
<h3 class="title">HEADER NUMBER TWO<h3>
<div class="area"></div>
<div class="something">IO field</div>
<input class="input"></input>
My intention is to identify an input element that belongs to the second panel.
Based on reliability check, when I have hardcoded XPATH gathered directly from the browser, sometimes wrong element is being identified (I assume that there are many scripts running when the page is being loaded, which impacts the reliability and stability). Therefore I would like to distinguish between elements based on the h3, which are the one and only difference between objects.
How can I do it?
When identifying elements one by one (so first the title, then its parent, and then moving down to the input), I receive an "element not interactable" exception which is not dependent from the time.
I am thinking of something like:
find //input[#class='input'] where one of ancestors contains /div/h3 which contains(text(), 'HEADER NUMBER TWO')
Obviously, I did not found any working solution for that, despite I spent more than a week with that.
Is it doable at all? If so, could you suggest me something, please? The structure in real is a little bit more complex, but I need just a pattern, hint, or clue.
Greetings!
You can locate the parent panel element based on it's child h3 with the desired title and then to locate the input element inside it.
The XPath to do so can look like the following:
"//div[#class='panel' and(.//h3[contains(.,'HEADER NUMBER ONE')])]//input"
Or even
"//div[#class='panel' and(contains(.,'HEADER NUMBER ONE'))]//input"
The selenium command using that XPath can look like:
driver.find_element(By.XPATH, "//div[#class='panel' and(contains(.,'HEADER NUMBER ONE'))]//input")
More explanations
The XPath
"//div[#class='panel' and(.//h3[contains(.,'HEADER NUMBER ONE')])]//input"
literally means:
Find element with div tag and class attribute value panel and having some child element inside it (this is .// comes for) containing HEADER NUMBER ONE text content.
Inside the above div element find input child element.
In Selenium you can find a set of elements:
inputs = driver.find_elements(By.CSS, 'input[class="input"]')
input_2 = inputs[1]
The input you need is the 2nd element in the list
When hitting inspect the element on a paragraph, I get directed to a tag. If it is empty, Where is the text that I see on the screen coming from?
I have attempted:
driver.find_elements_by_css_selector('the class of the textarea')
driver.find_elements_by_id("the id of the textarea")
driver.find_elements_by_class("the class of the textarea")
I've also tried the ladder methods with the parent divs of the text area. nothing.
Then I did the following:
I copied the text and cntrl+F to find it in the HTML, I was directed to a tag. I tried the following:
everything = driver.find_elements_by_tag_name("script")
for item in everything:
print(driver.execute_script(item.text))
I get a list of Nones printed out.
I have been stuck at this for days.
This is the tag:
<textarea style="width: 658px; height: 128px; overflow: auto;" autocomplete="off" id="ContentPH_description" name="ContentPH_description" role="textbox" aria-readonly="false" aria-required="false" aria-multiline="fals" class="x-form-textarea x-form-field vms-viewmode-view-set" readonly="" aria-labelledby="ContentPH_description_label" title="" aria-invalid="false" maxlength="10000" oldindex="0" tabindex="-1"></textarea>
I, unfortunately, cannot share a link or the full HTML of the page since it is work-related and you'd need a login to access the data I am trying to scrape.
What can I do to solve this?
I don't know if it will help you, but when I try to access visual hidden text elements (i.e. text from a collapsed tab), I always replace element.text to element.get_attribute('textContent') or element.get_attribute("innerText").
I am new to Robot Framework as well as writing automation using Pycharm and have run into an issue I cannot find an answer to. I have text boxes that the uid changes every time a change is made to the page. I have tried using an xpath but all of the text boxes appear to have the same starting ID of 56$551056-- so i cannot use xpath=//input[contains(#id='56$551056--')] without trying to add something additional to it.
Example TextBox1
<input type="text" class="gwt-TextBox WNN2" data-automation-id="textInputBox" tabindex="0" role="textbox" id="56$551056--uid74-input" dir="ltr" aria-invalid="false" xpath="1">
Example TextBox2
<input type="text" class="gwt-TextBox WNN2" data-automation-id="textInputBox" tabindex="0" role="textbox" id="56$551056--uid75-input" dir="ltr" aria-invalid="false" xpath="1">
There are 3-5 boxes in each section I am automating and they all seem to have the exact same code except for the uid. Removing ID and Class name (as these both throw a warning in ChroPath of being dynamic just gives me a string of //div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//div//li[2]//div[2]//div[1]//div[1]
Any help or direction on this greatly appreciated.
Update
So I have these paths connecting the ID and the Label but I would have to remove uid100 as this is the part that continues to change on the page. I have tried several different combinations to get this to work in RF but I cannot seem to get it exactly right. //label[#id='56$551056--uid100-formLabel'] //div[contains(text(),'First Name')] //*[#id="56$551056--uid100-input"]
<li class="WDSO WOTO" role="presentation" data-automation-id="formLabelRequired"><div class="WFSO WIRO"><label id="56$551056--uid430-formLabel" data-automation-id="formLabel" for="56$551056--uid430-input">First Name</label><div class="WISO wd-74ef43c8-48bb-445c-9b49-1a788d7c4b10" aria-hidden="true">First Name</div></div><div data-automation-id="decorationWrapper" id="56$551056" class="WJSO"><div class="WOAJ"><div class="WHN2 textInput WGN2 WJ5" data-automation-id="textInput" id="56$551056--uid430" data-metadata-id="56$551056" style="visibility: visible;"><input type="text" class="gwt-TextBox WON2" data-automation-id="textInputBox" tabindex="0" role="textbox" id="56$551056--uid430-input" dir="ltr" aria-invalid="false" aria-required="true"></div></div></div></li>
The best solution is to work with the developers to provide unique attributes for each input element.
If you can't do that, and if you can't easily uniquely identify an input element, then find the nearest element that you can uniquely identify, and use that as a base for finding the input element.
For example, if the input element is associate with a label -- and most are -- you can use the label element as part of the xpath. For example, //label[#text='First Name']//input. Exactly how you do that depends on the structure of the page - the input element might be the first sibling, or the first child, or some element elsewhere in the DOM but pointed to by an attribute in the label (eg: <label for= "56$551056--uid74-input">)
This question isn't unique to robot framework, it's common to just about every test automation framework.
Try to insert item label into your xpath instead of id. For example, if your textbox having the label Customer Name, then something will be like:
//label[text()='Customer Name']/../../input
(The dark part is my assumption)
So, you could get rid of the annoying dynamic ID
Please provide your full HTML, so I could give a better answer
Find the element by using xpath locators using the reference to parent element of the following element
<input type="text" class="gwt-TextBox WNN2" data-automation-id="textInputBox" tabindex="0" role="textbox" id="56$551056--uid74-input" dir="ltr" aria-invalid="false" xpath="1">
xpath example would be as follows:
xpath of parent//input[contains(#class,'TextBox')]
Basically I want to input invoices in Xero software for my job. The process is very simple, I have some values that I need to input in some slots. I have a big problem however. The xpath is dynamic (changes every time you refresh).
Basically it changes from something like this:
//*[#id="PaidToName_12ddc347c7bc4f5aa84c452f55660690_value"]
To something like this:
//*[#id="PaidToName_4fea44e4f8a844b4b630b4bf149490d8_value"]
So the numbers keep on changing.
I have tried a starts-with function however I am pretty sure that there are two XPATHs that starts with PaidToName or end with value, therefore this doesn't seem like a solution as I get this error message:
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
The other thing to note is that I see many elements that have the "input type hidden" in the HTML code which I am pretty sure play a role with that. Please let me know if there is anything I can do to help.
This is the code I have tried that doesn't work.
button = driver.find_element_by_xpath("//*[starts-with(#id,'PaidToName')]")
button.send_keys('lol')
This is the HTML code I am trying to retrieve
<input type="text" size="24" autocomplete="off" id="PaidToName_4fea44e4f8a844b4b630b4bf149490d8_value" name="PaidToName_4fea44e4f8a844b4b630b4bf149490d8_value" class="x-form-text x-form-field autocompleter x-form-focus" tabindex="10" style="width: 129px;">
You can use xpath with id and class combination, try this :
button = driver.find_element_by_xpath("//*[contains(#id,'PaidToName') and contains(#class,'x-form-text')]")
button.send_keys('lol')
Try below given locator.
driver.find_element_by_xpath("//input[contains(#id,'PaidToName') AND contains(#class,'x-form-text')]")
I am trying to select from a list of 3 buttons, but can't find a way to select them. Below is the HTML I am working with.
<input name="pollQuestion" type="radio" value="SRF">
<font face="arial,sans-serif" size="-1">ChoiceOne</font><br />
<input name="pollQuestion" type="radio" value="COM">
<font face="arial,sans-serif" size="-1">ChoiceTwo</font><br />
<input name="pollQuestion" type="radio" value="MOT">
<font face="arial,sans-serif" size="-1">ChoiceThree</font>
I can find it by using the following code:
for i in browser.find_elements_by_xpath("//*[#type='radio']"):
print i.get_attribute("value")
This outputs: SRF,COM,MOT
But I would like to select ChoiceOne. (To click it) How do I do this?
Use CSS Selector or XPath to select by value attribute directly, then click it.
browser.find_element_by_css_selector("input[type='radio'][value='SRF']").click()
# browser.find_element_by_xpath(".//input[#type='radio' and #value='SRF']").click()
Corrections (but OP should learn how to look up in documentation)
In Python binding, find_elements_by_css doesn't exist, it's called find_elements_by_css_selector. One should be able to look at the exception message and look back into documentation here and figure out why.
Notice the difference between find_element_by_css_selector and find_elements_by_css_selector? The first one finds the first matching element, the second one finds a list, so you need to use [0] to index. Here is the API documentation. The reason why I use the latter, is because I copied your code, which I shouldn't.
Selenium webdriver Radio button click
When i used xpath :
driver.find_element_by_xpath("//input[#id='id_gender2']").click()
radio button not selected
But I used css_selector :
driver.find_element_by_css_selector("input#id_gender1").click()
radio button selected
find_elements_by_css_selector worked for me,
browser.find_elements_by_css_selector("input[type='radio'][value='SRF']")[0].click()
First Radio button was not selected for me also. But after inserting Time it works for me.
driver.find_element_by_class_name("login").click()
driver.find_element_by_id("email_create").send_keys("testsel000#gmail.com")
driver.find_element_by_id("SubmitCreate").click()
time.sleep(2)
driver.find_element_by_css_selector("#id_gender2").click()
Consider that you have a radio button to select either of the two options, "Male or "Female". Then try using the following :- This is in Python (Selenium).
driver.find_element_by_xpath("//label[contains(text(),'Male')]").click()
browser.find_elements_by_xpath(".//input[#type='radio' and #value='SRF']")[0].click
This ended up being the fix. I was getting errors without the [0] there, that a list does not have a click() attribute (even though there was only 1 match). Thanks for the help user1177636!