I have a dropdown menu and I need to check its entries. If there is no entry , I can add new entries, if there is only one entry I remove it and add new entries and when I have many entries (>=2) I cannot proceed to adding entries. I can check it via person_rem_btn. If I have only one button doc_person_table:0:person_rem_btn I can proceed If I have a second button doc_person_table:1:person_rem_btn I cannot proceed.
I get this exception:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id='frmMain:doc_person_table:1:person_rem_btn']/span[1]"}
However, that's the point, this element may not be available, I just check its existence. I would appreciate any help. Here is my code:
if driver.find_element_by_xpath("//*[#id='frmMain:doc_person_table:1:person_rem_btn']/span[1]") == True:
print ("there are already many entries")
driver.close()
elif (driver.find_element_by_xpath("//*[#id='frmMain:doc_person_table:1:person_rem_btn']/span[1]") == False and driver.find_element_by_xpath("//*[#id='frmMain:doc_person_table:0:person_rem_btn']/span[1]") == True):
print ("there is only one entry, it will be removed to proceed")
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//*[#id='frmMain:doc_person_table:0:person_rem_btn']/ span[1]"))).click()
else:
print ("there is no entry, you can proceed")
find_element_by_xpath doesn't return True or False, it returns WebElement or throws NoSuchElementException. You can use find_elements_by_xpath to get a list and check if this list contains any elements. Start with waiting for an unrelated element that can indicate the page is loaded
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, "//*[#id^='frmMain:doc_person_table")))
# assuming this element will always appear when the page is loaded
elements = driver.find_elements_by_xpath("//*[#id='frmMain:doc_person_table:1:person_rem_btn']/span[1]")
if elements: # more verbose if len(elements) > 0
print ("there are already many entries")
driver.close()
else:
elements = driver.find_elements_by_xpath("//*[#id='frmMain:doc_person_table:0:person_rem_btn']/span[1]")
if elements:
print ("there is only one entry, it will be removed to proceed")
elements[0].click()
else:
print ("there is no entry, you can proceed")
There are several approaches you can adapt and one of the approach would be to create a List of the dropdown entries inducing WebDriverWait for the visibility_of_all_elements_located() and probe the list size:
Using CSS_SELECTOR:
list = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "[id*='doc_person_table'][id$='person_rem_btn']>span")))
if not list:
print ("there is no entry, you can proceed")
# other steps
elif len(list) == 1
print ("there is only one entry, it will be removed to proceed")
# other steps
else:
print ("there are already many entries")
break
Using XPATH:
list = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//*[contains(#id, 'doc_person_table') and contains(#id, 'person_rem_btn')]/span")))
if not list:
print ("there is no entry, you can proceed")
# other steps
elif len(list) == 1
print ("there is only one entry, it will be removed to proceed")
# other steps
else:
print ("there are already many entries")
break
Related
I faced a task when I need to add a condition after checking all amounts on the site. Code checks amount on the website and select them if they are equal to the amount I have in report, if no move to the next line. Now my code looks like that and if there is nothing selected, it just stops:
a = "€ 406.61"
n = 1
while n <= 15:
content = wait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//*[#id="available-expenses"]/div/section/div/div/div[2]/table/tbody/tr['+ str(n) +']/td[7]/div/div'))).text
if a == content:
wait(driver, 30).until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[2]/div/div/div/div[1]/div/div[2]/div/section/div/div/div[2]/table/tbody/tr['+ str(n) +']/td[1]/input')))
driver.find_element(By.XPATH, '/html/body/div[2]/div/div/div/div[1]/div/div[2]/div/section/div/div/div[2]/table/tbody/tr['+ str(n) +']/td[1]/input').click()
n += 1
else:
n += 1
# ctypes.windll.user32.MessageBoxW(0, "No expense", "Warning!", 16)
If nothing is selected, the message should be displayed that there is "no expense" (but I don't know how I should write this condition).
i wanna know if element appear then disappear i want to apply it in this code
i know that internet is back by a text appear when internet is gone or its back
except:
time.sleep(3)
if driver.find_element(By.CLASS_NAME, "KhLQZTRq").size['width'] != 0 :
print ('internet lost')
while True:
time.sleep(5)
if driver.find_element(By.CLASS_NAME, "KhLQZTRq").size['width'] == 0 :
print("internet back")
else:
continue
else:
print("nothing happen")
This is working fine:
if driver.find_element(By.CLASS_NAME, "KhLQZTRq").size['width'] != 0
and it print 'internet lost' when the the element appear
But this is not working:
if driver.find_element(By.CLASS_NAME, "KhLQZTRq").size['width'] == 0
i just want it to print " internet back " if the element is no longer present
If the element appears or disappears you could write
if driver.find_element(By.CLASS_NAME, "KhLQZTRq"):
It will return True if the element exists and False if it doesn't
I am trying to scrape a website and fairly new to Python. I have managed to come up with below code. The problem however is it goes into an infinite loop after reaching the last page i.e Next button is greyed out.
Also i don't think i am catching the Stale Element properly here. Any help would be greatly appreciated!`
pages_remaining = True
while pages_remaining:
button=driver.find_element_by_class_name("arrow-right")
href_data = button.get_attribute('href')
if href_data is not None:
soup=BeautifulSoup(driver.page_source,"html.parser")
data = soup.find_all("div",{"class":"shelfProductStamp-content row"})
count = 1
for item in data:
ProductText=item.find("a",attrs={"class":"shelfProductStamp-imageLink"})["title"]
if item.find("span",attrs={"class":"sf-pricedisplay"}) is not None:
Price=item.find("span",attrs={"class":"sf-pricedisplay"}).text
else:
Price=""
if item.find("p",attrs={"class":"sf-comparativeText"}) is not None:
SubPrice1=item.find("p",attrs={"class":"sf-comparativeText"}).text
else:
SubPrice1=""
if item.find("span",attrs={"class":"sf-regoption"}) is not None:
Option=item.find("span",attrs={"class":"sf-regoption"}).text
else:
Option=""
SubPrice=str(SubPrice1)+"-"+str(Option)
SaleDates=item.find("div",attrs={"class":"sale-dates"}).text
urll2=driver.current_url
PageNo=driver.find_element_by_class_name("current").text
writer.writerow([ProductText,Price,SubPrice,SaleDates,PageNo])
count+=1
try:
def find(driver):
element = driver.find_element_by_class_name("arrow-right")
if element:
return element
else:
pages_remaining=False
#driver.quit()
time.sleep(10)
driver.implicitly_wait(10)
element = WebDriverWait(driver, 60).until(find)
driver.execute_script("arguments[0].click();", element)
except StaleElementReferenceException:
pass
else:
break
Thanks
When you set pages_remaining = False inside the find() function, that is a local variable. It is not the same variable as pages_remaining in the outer loop.
If you want to do it that way, you'll need to make it a global.
Thanks for your help here. I managed to fix this by simply adding another if statement at the end and swapping the time.sleep(10) as below
try:
def find(driver):
element = driver.find_element_by_class_name("arrow-right")
if element:
return element
driver.implicitly_wait(10)
element = WebDriverWait(driver, 60).until(find)
driver.execute_script("arguments[0].click();", element)
time.sleep(10)
except StaleElementReferenceException:
pass
if href_data is None:
break
With Python, Selenium and Webdriver, a need to subsequently click elements found by texts, using the find_element_by_xpath() way on a webpage.
(an company internal webpage so excuse me cannot provide the url)
By xpath is the best way but there are multiple texts I want to locate and click.
It works when separately like:
driver.find_element_by_xpath("//*[contains(text(), 'Kate')]").click()
For multiple, here is what I tried:
name_list = ["Kate", "David"]
for name in name_list:
xpath = "//*[contains(text(), '"
xpath += str(name)
xpath += "')]"
print xpath
driver.find_element_by_xpath(xpath).click()
time.sleep(5)
The output of the print xpath looked ok however selenium says:
common.exceptions.NoSuchElementException
You can simplify your code as below:
for name in name_list:
driver.find_element_by_xpath("//*[contains(text(), '%s')]" % name).click()
or
for name in name_list:
try:
driver.find_element_by_xpath("//*[contains(text(), '{}')]".format(name)).click()
except:
print("Element with name '%s' is not found" % name)
Use string formatting. Put a placeholder into the xpath string and fill it with a variable value:
name_list = ["Kate", "David"]
for name in name_list:
xpath = "//*[contains(text(),'{}')]".format(name)
driver.find_element_by_xpath(xpath).click()
Try this:
name_list = ["Kate", "David"]
for name in name_list:
xpath = "//*[contains(text(), '" + str(name) + "')]" # simplified
print xpath
list = driver.find_elements_by_xpath(xpath) # locate all elements by xpath
if len(list) > 0: # if list is not empty, click on element
list[0].click() # click on the first element in the list
time.sleep(5)
This will prevent from throwing
common.exceptions.NoSuchElementException
Note: also make sure, that you using the correct xPath.
My problem is that
1st part:
I have to fetch all the href values dynamically
2nd part:
After fetching I need to click on href value which are required(ex:i mean if dynamically I fetch 20 href value in that only 8 I need to click )
And catch is that the href value keeps on changing (1st part I know how to do but 2 part I am not sure how to implement)
hamburgerDrop = driver.find_element(By.XPATH,"//tr[#data-category-id='15']/td[3]")
elements = hamburgerDrop.find_elements(By.TAG_NAME,"a")
for link in elements:
if link.get_attribute('href'):
link.click()
print("the element found")
driver.back()
time.sleep(4)
break
else:
print("element is not found")
From the above code which I have written I am able to click only one href value if I want to click on the second I cant do it
for example:( thing is out of 20 href value i want to click only 8 )
So i wrote a code like this
def find_products(self):
elements = self.captureLinks(self.category_container,"xpath","a,li,div")
for link in elements:
if link.get_attribute('href') = 'https://example.com,/c/announcements' :
link.click()
self.log.info("The products link is found")
time.sleep(3)
else:
self.log.info("The products link is not found")
self.back()
time.sleep(5)
when my manager reviewed this code ,they told me with out comparing with href value it should click on the respective link .
def find_products(self):
elements = self.captureLinks(self.category_container,"xpath","a,li,div")
for link in elements:
if "announcements" in link.get_attribute('href') :
link.click()
self.log.info("The products link is found")
time.sleep(3)
else:
self.log.info("The products link is not found")
self.back()
time.sleep(5)
return elements
so i changed the code like this but when i executed i am getting the error
TypeError: argument of type 'NoneType' is not iterable
The problem is that your loop is being ended with break. Remove this and the loop should continue