I can't get element by class - python

I am working with element like
<div class="slick-track" style="opacity: 1; width: 9140px; left: 0px;" role="listbox">
when trying to start using Robot Framework for Python for creating autotests
I need to check this element exist, and, its items. How can I do that?

You can simply use:
Page should contain element css=div.slick-track
Or even better, in order to avoid possible delay issues (like an element taking a few seconds to be displayed on the page)
Wait until page contains element css=div.slick-track
Comment: Didn't quite understand what you meant by "and, its items".

If i understood your question properly..
To locate the element by class:
Location should contain class:slick-track
to check its attributes:
element attribute value should be class:slick-track role listbox
let me know if this is what you meant.

Related

How do I click on this item using Selenium?

Im trying to automate the download of report using selenium. To get to the page where the report is I have to click on an image with this code
<div class="leaflet-marker-icon single-icon-container running hover asset leaflet-zoom-hide leaflet-clickable" tabindex="0" style="margin-left: -22px; margin-top: -41px; width: 44px; height: 44px; opacity: 1; transform: translate3d(525px, 238px, 0px); z-index: 238;"><div class="icon-value" lid="219058"></div></div>
I tried with
wtg = driver.find_elements_by_class_name(
"leaflet-marker-icon single-icon-container running hover asset leaflet-zoom-hide leaflet-clickable")
wtg.click()
but nothing happens.
There are 7 elements with the same class, and a unique "id " tha looks like lid="219058" but I dont know how to select that.
leaflet-marker-icon single-icon-container running hover asset leaflet-zoom-hide leaflet-clickable contains multiple class names while driver.find_element_by_class_name method intends to get a single class name.
I can't give you a correct locator for this element since you didn't share the page link, however if you wish to locate that element based on these class names combination you can use CSS Selector or XPath as following:
wtg = driver.find_element_by_css_selector(".leaflet-marker-icon.single-icon-container.running.hover.asset.leaflet-zoom-hide.leaflet-clickable")
wtg.click()
Or
wtg = driver.find_element_by_xpath("//*[#class='leaflet-marker-icon single-icon-container running hover asset leaflet-zoom-hide leaflet-clickable']")
wtg.click()
Also you should use driver.find_element_by_class_name, not driver.find_elements_by_class_name since driver.find_elements_by_class_name will give you a list of web elements, not a single web element that can be clicked directly.
Alternatively you can use the first index inside the list of received web elements as described by FLAK-ZOSO
Generally speaking, the best practice when building web scrapers is to always use xpath, since xpath can apply all the filters (id, class, etc) in a more flexible way (in some cases though, performance in selenium might be decreased).
I recommend you check this article on how to write xpaths for various needs: https://www.softwaretestinghelp.com/xpath-writing-cheat-sheet-tutorial-examples/
For your particular use case, I would use:
driver.find_element_by_xpath('//div[#lid="219058"]')
This will actually click on the inner div (notice how the lid is actually inside the nested div). If you wish to click on the outer div you can use:
driver.find_element_by_xpath('//div[#lid="219058"]/parent::div')
I again recommend you to learn Xpath syntax and always use it, it is way easier to manipulate than the other selenium selectors and is also faster in case you ever choose to implement a C compiled html parser such as lxml to parse the elements.
Remember that driver.find_elements_by_class_name() returns a list.
You have to do something like this when using this get/find method:
driver.find_elements_by_class_name('class')[0] #If you want the first of the page
In your case you need to use the css_selector because you have multiple classes, like suggested by #Prophet.
You can also use only one of the classes and simply use the class_name selector.
In your case, if you need the first element of the page with that class, you have to add [0].

Issue in locating web element selenium

I am unable to locate a web element on a website, The web elements of the website are dynamic and the elements which i am trying to locate have very similar attributes to that of others with just small differences like changes in integers. These integers also change when i refresh the page so i am unable to locate can someone help?
I tried following but there maybe mistakes in syntaxes:
With contains text = WebDriverWait(browser, 15).until(EC.presence_of_element_located( (By.XPATH,"//div[contains(text(),'Type here...')]") ))
Absolute Xpath and Rel Xpath(these changes)
Contains sibling, contains parents but the parent and sibling elements are also unable to locate
here is the html of the element <div contenteditable="true" class="cke_textarea_inline cke_editable cke_editable_inline cke_contents_ltr placeholder cke_show_borders" tabindex="0" spellcheck="true" role="textbox" aria-label="Rich Text Editor, editor15" title="Rich Text Editor, editor15" aria-describedby="cke_849" style="position: relative;" xpath="1">enter question here</div>
There are spaces being added () which some time cause issue, please deleting that space. Also if you can share html then we might be able to help. WebDriverWait(browser,15).until(EC.presence_of_element_located((By.XPATH,"//div[contains(text(),'Type here...')]")))
I removing space doesn't work then you can try below xpath-
//div[text()='enter question here'][contains(#aria-label,'Rich Text Editor')]
If there are really no attributes you would consider reliable, you can access the element by the text inside of it. I'd recommend two things: Don't do this unless you find no other choice, and don't just use //div, add as much XPATH info to the path as you can.
driver.find_element_by_xpath('//div[text()="enter question here"]')
OR
driver.find_element_by_xpath('//div[contains(text(),"enter question")]')

selenium exact match based on text

If I have some HTML:
<span class="select2-selection__rendered" id="select2-plotResults-container" role="textbox" aria-readonly="true" title="50">50</span>
And I want to find it using something like:
driver.find_element_by_xpath('//*[contains(text(), "50")]')
The problem is that there is 500 somewhere before on the webpage and it's picking up on that, is there way to search for a perfect match to 50?
Instead of contains, search for a specific text value:
driver.find_element_by_xpath('//*[text()="50"]')
And if you know it will be a span element, you can be a little more specific:
driver.find_element_by_xpath('//span[text()="50"]')
Note that your question asks how to find an element by its text value. If possible and would apply to your situation, you should look for a specific class or id, if known and consistent.
You can search for it by its absolute Xpath. For that, inspect the page and find the element. Then right-click it and copy its Xpath or full Xpath.
Otherwise you can use the id:
driver.find_element_by_id("select2-plotResults-container")
Here is more on locating elements.
use something like this
msg_box=driver.find_element_by_class_name('_3u328') and driver.find_element_by_xpath('//div[#data-tab = "{}"]'.format('1'))

How to find the second occurence of .find_element_by_class_name?

I have tried,
browser.find_element_by_class_name('("my_class")[1]')
browser.find_element_by_class_name('("my_class")[position()=1]')
browser.find_element_by_class_name("my_class")[1]
The "easy" answer
The simple way to get what you want is to use the plural form of the locator method you are already using, find_elements_by_class_name(). The plural forms return a list instead of just the first match so in your case you would use
find_elements_by_class_name("my_class")[1]
The find_elements_* method returns a list and the [1] at the end specifies to return only the second item in the collection (the index starts at 0).
What I would use
I generally don't use *_by_class_name() because it's rare that I'm only looking for a class. I typically at least specify the tag name also, e.g. div.my_class. Another option, and the one I typically use, is a CSS selector. CSS selectors should be preferred over XPath because of better performance, better support, etc.*
An example
<div class="class1 class2 class3">123</div>
<div class="class2">2</div>
<div class="class3">3</div>
<div class="class1 class2">12</div>
<div class="class1 class3">13</div>
<div class="class1">1</div>
<div class="class2 class3">23</div>
If you had the above HTML and wanted the second instance of "class1", you would use
driver.find_elements_by_css_selector("div.class1")[1]
Another advantage of CSS selectors over XPath is that CSS selectors look for the class name amongst multiple class names on an element where XPath can only do a text search which can lead to false or missed matches. The CSS selector above would return 4 total elements: "123", "12", "13", "1". The index [1] returns only the second instance, "12".
If you used the XPath that DebanjanB suggested,
//*[#class='my_class'][position()=2]
it would return nothing. That's because there's only one element that has the exact string "my_class" as the class. It misses all the other elements that contain but are not only "my_class". You could improve it to find them all but it still has all the downfalls of XPath vs CSS selectors, it's much longer, and so on...
See the Selenium-python docs for more info on ways to find elements.
*If you need more details on the why, there's a number of articles already addressing this or look through the videos on the Selenium Conference YT channel and watch some of the keynote addresses by Simon Stewart or other Selenium contributors.
Don't forget
You may need to use a wait if the page is slow to load.
On some lazy loading pages you will need to scroll the page to get the additional elements to load.

How can I get random ID of element?

I have a situation, the id always change for a random one,
so I can't use find_element_by_id
have some divs above,
<div class="x-tree-view x-fit-item x-tree-view-default x-unselectable"
id="treeview-2234"
tabindex="0"
componentid="componentstree-1118"
style="overflow: auto;
margin: 0px; height: 443px; width: 228px;">
<div class="x-grid-item-container"
style="width: 228px;
transform:
translate3d(0px, 0px, 0px);">
<table id="treeview-2234-record-879"
data-boundview="treeview-2234"
data-recordid="879"
data-recordindex="0"
class="x-grid-item x-grid-item-selected"
cellpadding="0"
cellspacing="0"
style="width:100%;">
I already tried:
Use recordid, but sometimes the recordid repeats.
By class_name, but sometimes the class repeats.
OF course by id, but as I've already said, when page refreshes, it becomes another id
By treeview-2234 root...fail
I'm another victim of EXt, what can I do?
If the ID is different each time the page is refreshed then it is impossible to select the element by ID. Instead, you need to find a way to select the element by something else which is unique. This could be by using one of the attributes (data-boundview, data-recordid,....), or by selecting the path to the table element via the HTML structure which is loaded whenever the page is refreshed.
I would then use driver.find_element_by_xpath() to select the element. For example, you could select the element by attribute as follows:
driver.find_element_by_xpath('//table[#data-boundview="treeview-2234"]')
Alternatively, if you know the HTML structure, you could do something along the following lines:
driver.find_element_by_xpath('//div[#id="ancestor-div"]/div[#id="parent-div"]/table')
I would try xpath on the dom as expected. You may need to grab the not changing parent dom of the changing dom and get inside child from it by many ways esp in xpath-
Use contains function-
driver.find_element_by_xpath("//div[#class= 'x-grid-item-container']/table[contains(#data-boundview,'treeview-')]")
It will grab all data-boundview that has value starts with treeview- If there are more data-boundview with value starts with treeview- then try to grab non-changing parent first and then dig into it to get child as i mentioned earlier.
if ur id changes randomly, use the unchanged classes, like below:
driver.find_element_by_css_selector("div.x-tree-view.x-fit-item.x-tree-view-default.x-unselectable");
this will select the first div.To choose second div, use
driver.find_element_by_css_selector("div.x-grid-item-container");
if the table is under this div, try like this:
driver.find_element_by_css_selector("div.x-grid-item-container>table.x-grid-item.x-grid-item-selected");
If id="treeview-2234" is constant in your id, you can search for id which contains it:
driver.find_element_by_css_selector('[id*="treeview-2234"]');

Categories

Resources