Python Selenium to select "menuitem" from "menubar" - python

I have a code that clicks a button on a web page, which pops up a menubar. I would like to select a menuitem from the choices that appear, and then click the menuitem (if possible); however, I'm at a roadblock.
Here is the relevant part of the code so far:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('URL')
Btn = driver.find_element_by_id('gwt-debug-BragBar-otherDropDown')
Btn.click() #this works just fine
MenuItem = driver.find_element_by_id('gwt-uid-463') #I'm stuck on this line
MenuItem.click()
Here is the error it's throwing, based on what I have written:
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element
Note: it appears that the id for this element changes each time the page loads (which is probably the cause of the error). I've tried searching for the element by find_element_by_class_name as well, but it has a compound class name and I keep getting an error there, too.
Here's the code of the menubar:
<div class="gux-combo gux-dropdown-c" role="menubar" id="gwt-debug-BragBar-otherMenu">
and the menuitem I want:
<div class="gux-combo-item gux-combo-item-has-child" id="gwt-uid-591" role="menuitem" aria-haspopup="true">text</div>
I'm looking for a way to select the menuitem. Thanks!

Try this xpath
driver.find_element_by_xpath('//div[#role='menuitem' and .='text']').click();
It will check for the 'div' element having attribute 'role' as 'menuitem' and having exact text as 'text'.
Say, there is a menuitem "Lamborghini AvenTaDor" under your menu. So, the code for that will become:
driver.find_element_by_xpath('//div[#role='menuitem' and .='Lamborghini AvenTaDor']').click();

You can find the element by xpath and check that the id attribute starts with gwt-uid-:
menu_item = driver.find_element_by_xpath('//div[starts-with(#id, "gwt-uid-")]')
menu_item.click()
You can also apply additional checks if needed, e.g. check role attribute as well:
driver.find_element_by_xpath('//div[starts-with(#id, "gwt-uid-") and #role="menuitem"]')

Related

Unable to Click on Dropdown using Python Selenium

I'm trying to select an element from a dropdown but getting an error.
Here is the HTML:
<select id="childContextDDL" data-filter="contains" data-role="dropdownlist" data-template="dcf-context-picker" data-value-field="Value" data-text-field="DisplayText" data-bind="events: { change: childContextListChange }, source: childContextList.ChildContextList" style="display: none;">
<option value="1">NATION</option>
<option value="12">ATLANTIC</option>
<option value="16">CHARLOTTE, NC</option>
And this is the code that I'm trying to run:
mySelect = Select(driver.find_element_by_id("childContextDDL"))
print('MySelect is: ',mySelect)
mySelect.select_by_visible_text('ATLANTIC')
I'm getting this error:
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable: Element is not currently visible and may not be manipulated
What's the possible reason for getting this error? I'm very new to Selenium.
I also want to click on that element after selecting it.
The problem was that the style within the html was set to none. So I had to first change that style to block to make it visible and then proceed with the clicking operation.
Here's the code that worked:
driver.execute_script("document.getElementById('childContextDDL').style.display = 'block';")
mySelect = Select(driver.find_element_by_id("childContextDDL"))
print('MySelect is: ',mySelect)
mySelect.select_by_visible_text('ATLANTIC')
randomClick = driver.find_element_by_id('dcf-user-info')
randomClick.click()
I guess the mySelect element (the dropdown menu) is not visible.
So please try the following:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
mySelect = Select(driver.find_element_by_id("childContextDDL"))
actions.move_to_element(mySelect).perform()
mySelect.select_by_visible_text('ATLANTIC')
If the above doesn't work (I can't see the actual site you are working on), the following can work instead in the element has to be tapped to become enabled
action = TouchActions(driver)
action.tap(mySelect).perform()
mySelect.select_by_visible_text('ATLANTIC')
If it says it is not currently visible, you should try pausing the code with one of this options:
time.sleep(1) #This states to your code to stop for 1 second and the continue with the work.
WebDriverWait(driver, 10).until(EC.element_to_be_visible(BY.value, "12")) # tells the driver to wait a maximum of ten seconds until the value "12" is visible for the driver.

How to locate the element in this?

I am new to Selenium programming and have an issue.
z=driver.find_elements_by_xpath("/html/body/div[3]/div/div[3]/div/div[2]/div/div/div[2]/div/table[1]/tbody/tr/td[2]/div/div[3]/input[1]")
text = input("Gebietsdefinition: ")
z[0].send_keys(text)
time.sleep(2)
xpath : /html/body/div[3]/div/div[3]/div/div[2]/div/div/div[2]/div/table[1]/tbody/tr/td[2]/span
id : dijit_form_Button_18
class : dijit dijitReset dijitInline SendRequest dijitButton
this is the full xpath, class & id of the button. But when I use the command,
driver.find_element_by_id("dijit_form_Button_18").click()
it executes in python without any error, but the webdriver stays the same.
NB: The button changes its class when I move the cursor over the button to "Hover" and changes to "Button ActiveFocused" when I click.
I hope somebody can shed some light into this. Thank you in advance.
Basically, you are tying to say that no error comes and click effect is also not visible.
Most probably, Selenium is clicking the element before it is clickable that is before the element is enabled to be clicked.
You can:
Introduce some delay in between using wait
Or you can use webdriverwait class and that will help
Without looking at the HTML with you, I hope that I can answer your population question. For the population question, you should import the following
from selenium import webdriver
from selenium.webdriver.common.by import By
and then you can try to populate your textbox with the following steps
element = driver.find_element(By.XPATH, "Your xpath here")
customText = "Your text here"
element.send_keys(customText)
# Gets the text that displays inside of our textbox after population
inputText = driver.find_element(By.XPATH, "Your xpath here").get_attribute('value')
if inputText.lower() != customText.lower():
raise Exception("Textbox failed to populate")
If the input tag is a button and has the following class elements
dijit dijitReset dijitInline SendRequest dijitButton
then you can use the following xpath to get your button
//input[contains(#class, 'SendRequest') and contains(#class, 'dijitButton')]
and then click it by using the following command
driver.find_element(By.XPATH, "//input[contains(#class, 'SendRequest') and contains(#class, 'dijitButton')]").click()
I hope this helps point you in the right direction.

Can not locate element inside the frame WHEN running all code

I want to locate the elements of a popup on some page,
the popup html is written in an iframe,
also the popup is triggered by clicking a link on the main page.
The weird thing is, if I run the whole code, I can not locate the 'target' element:
dr = webdriver.Chrome('chromedriver.exe', options=chrome_options)
modify = (By.CLASS_NAME, "modify")
ec_visible(dr, modify).click()
popup = (By.CLASS_NAME, "add-addr-iframe")
dr.switch_to.frame(ec_visible(dr, popup))
target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
def ec_visible(driver, locator):
return WebDriverWait(driver, 5).until(EC.visibility_of_element_located(locator))
But, if I first open the popup then locate, it works.
First:
modify = (By.CLASS_NAME, "modify")
ec_visible(dr, modify).click()
#popup = (By.CLASS_NAME, "add-addr-iframe")
#dr.switch_to.frame(ec_visible(dr, popup))
#target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
#ec_visible(dr, target).click()
Then: (works too if I manually open the popup and run this code)
#modify = (By.CLASS_NAME, "modify")
#ec_visible(dr, modify).click()
popup = (By.CLASS_NAME, "add-addr-iframe")
dr.switch_to.frame(ec_visible(dr, popup))
target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
Appreciate if you can point out my problem!
Here is the exception from shell:
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
This is the html screenshot,
sometimes the content in iframe can not even be seen.
iframe not extendable
when iframe extendable
7/26 update
I am wondering whether I asked the right question which may lead you guys just focusing on my code part. Since my code works(seperately), the elements and frames approach are good.
I step back and find one detail which may help but I don't know how it matters.
Here are the two shots about ctrl-F some element in the page source:
Normal result: target found and highlighted
Weird result: target found and no highlight
I mean when the page exists 'weird result', my code does not work.
PS. The page is the order-confirmation part of an e-commerical site, but the site groups its goods into two types which led to TWO types order page.
For ifarmes you have frame_to_be_available_and_switch_to_it as the EC.
So try this:
WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.CLASS_NAME, "add-addr-iframe")))
target = (By.CLASS_NAME, "span.cndzk-entrance-division-header-click")
ec_visible(dr, target).click()

Use python and selenium to delete my comments in reddit

I am trying to write a script to delete all my comments on my profile in Reddit.
So I am currently using Selenium to log-in and try to delete my comments, however I am stuck at the point when after my script press delete on my comment and it changes to "Are you sure Yes/No" then it can't find the "Yes" element by Xpath. The following code throws the error:
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementNotVisibleException: Message:
Element is not currently visible and so may not be interacted with
Stacktrace:
My code is as follows:
del_button = driver.find_element_by_xpath("//*[contains(#id,'thing_"+delete_type+"')]//div[2]/ul/li[7]/form/span[1]/a")
del_button.click()
time.sleep(3)
yes_button = driver.find_element_by_xpath("//*[contains(#id,'thing_"+delete_type+"')]//div[2]/ul/li[7]/form/span[1]//a[1]")
yes_button.click()
time.sleep(3)
As there could be several hidden elements with same attributes on page, you might need to use index to click on exact element:
driver.find_elements_by_xpath('//a[#class="yes"]')‌​[N].clic‌​k() # N is the index of target link
I f you can't define exact index, you can use below code:
from selenium.common.exceptions import ElementNotVisibleException
for link in driver.find_elements_by_xpath('//a[#class="yes"]')‌:
try:
link.click()
break
except ElementNotVisibleException:
pass

Python+Selenium, can't click the 'button' wrapped by span

I am new to selenium here. I am trying to use selenium to click a 'more' button to expand the review section everytime after refreshing the page.
The website is TripAdvisor. The logic of more button is, as long as you click on the first more button, it will automatically expand all the review sections for you. In other words, you just need to click on the first 'more' button.
All buttons have a similar class name. An example is like taLnk.hvrIE6.tr415411081.moreLink.ulBlueLinks. Only the numbers part changes everytime.
The full element look like this:
<span class="taLnk hvrIE6 tr413756996 moreLink ulBlueLinks" onclick=" var options = {
flow: 'CORE_COMBINED',
pid: 39415,
onSuccess: function() { ta.util.cookie.setPIDCookie(2247); ta.call('ta.servlet.Reviews.expandReviews', {type: 'dummy'}, ta.id('review_413756996'), 'review_413756996', '1', 2247);; window.location.hash = 'review_413756996'; }
};
ta.call('ta.registration.RegOverlay.show', {type: 'dummy'}, ta.id('review_413756996'), options);
return false;
">
More </span>
I have tried several ways to get the button click. But since it is an onclick event wrapped by span, I can't successfully get it clicked.
My last version looks like this:
driver = webdriver.Firefox()
driver.get(newurl)
page_source = driver.page_source
soup = BeautifulSoup(page_source)
moreID = soup.find("span", class_=re.compile(r'.*\bmoreLink\b.*'))['class']
moreID = '.'.join(moreID[0:(len(moreID)+1)])
moreButton = 'span.' + moreID
button = driver.find_element_by_css_selector(moreButton)
button.click()
time.sleep(10)
However, I keep getting the error message like this:
WebDriverException: Message: Element is not clickable at point (318.5,
7.100006103515625). Other element would receive the click....
Can you advise me on how to fix the problem? Any help will be appreciated!
WebDriverException: Message: Element is not clickable at point (318.5, 7.100006103515625). Other element would receive the click....
This error to be occur when element is not in the view port and selenium couldn't click due to some other overlay element on it. In this case you should try one of these following solution :-
You can try using ActionChains to reach that element before click as below :-
from selenium.webdriver.common.action_chains import ActionChains
button = driver.find_element_by_css_selector(moreButton)
ActionChains(button).move_to_element(element).click().perform()
You can try using execute_script() to reach that element before click as :-
driver.execute_script("arguments[0].scrollIntoView(true)", button)
button.click()
You can try using JavaScript::click() with execute_script() but this JavaScript::click() defeats the purpose of the test. First because it doesn't generate all the events like a real click (focus, blur, mousedown, mouseup...) and second because it doesn't guarantee that a real user can interact with the element. But to get rid from this issues you can consider it as an alternate solution.
driver.execute_script("arguments[0].click()", button)
Note:- Before using these options make sure you're trying to interact with correct element using with correct locator, otherwise WebElement.click() would work well after wait until element visible and clickable using WebDriverWait.
Try using an ActionChains:
from selenium.webdriver.common.action_chains import ActionChains
# Your existing code here
# Minus the `button.click()` line
ActionChains(driver).move_to_element(button).cli‌​ck().perform()
I have used this technique when I need to click on a <div> or a <span> element, rather than an actual button or link.

Categories

Resources