I have html like so:
<div class="card">
<div>Foo</div>
<a>View Item</a>
</div>
<div class="card">
<div>Bar</div>
<a>View Item</a>
</div>
I want to select the card matching "Bar" and click the "View Item" link. I tried
cards = browser.find_elements_by_class_name('card')
for card in cards:
if card.find_element_by_partial_link_text('Bar'):
item_anchor = card.find_element_by_partial_link_text('View Item')
item_anchor.click()
However I get the error:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"partial link text","selector":"Bar"}
Try using the EC and below xpath.
Option 1:
Check if the link exist and then click (you can add the attributes to link in the xpath, if you are looking for any specific link)
link =WebDriverWait(driver,10).until(EC.presence_of_element_located((By.XPATH,"//div[#class='card' and div[normalize-space(.)='Bar']]/a")))
if (link):
link.click()
Options 2:
Using different xpath and len
links =WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.XPATH,"//div[#class='card']/div[normalize-space(.)='Bar']/following-sibling::a[normalize-space(.)='View Item']")))
if len(links)>0:
links[0].click()
Option 3:
If you are not sure there are any levels present between B and A you can use the below xpath.
links =WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.XPATH,"//div[normalize-space(.)='Bar']/ancestor::div[#class='card']//a[normalize-space(.)='View Item']")))
if len(links)>0:
links[0].click()
If you want to click on View Item of Bar, you can directly use this xpath :
//div[text()='Bar']/following-sibling::a[text()='View Item']
However introducing webdriver wait would a great idea for stability as mentioned by #supputuri
There are two ways to handle this situation based on your UI behavior:
1) If UI is fixed, use this xpath to identify and use click() to click on it.
//*[#class='card']/div[.='Bar']/following-sibling::a
2) If you are taking data from any external sources (like Database or Excel), pass your expected value (like Bar or Foo) as a parameter to the xpath method like below:
Define a class called Element like as below:
public class Element {
private WebElement element;
private WebDriver driver;
private String xpath;
// Constructor will wrap web element into Object and will allow to use any of the method declared below
public Element(String xpath) {
this.driver = new ChromeDriver();
this.xpath = xpath;
this.element = this.driver.findElement(By.xpath(this.xpath));
}
public void click() {
this.element.click();
}
}
Create POM class and write a methods like below:
public class PageObjectClass {
private Element elementToClick(String value) {
return new Element("//*[#class='card']/div[.='" + value + "']/following-sibling::a");
}
public void clickOnViewItemsLink(String value) {
this.elementToClick(value).click();
}
}
By this way, you can click on any of View Item link just by passing value as a parameter
This can be achieved by a single line of code by using the correct xpath.
driver.findElement(By.xpath("//div[text()='Bar']/following-sibling::a[text()='View Item']")).click();
Related
I have a paragraph element as follows:
<p>You have logged in successfully. <em>LOGOUT</em></p>
Clicking on "LOGOUT" will initiate a logout procedure (e.g display a confirmation prompt).
How do I simulate this clicking on "LOGOUT" using Selenium WebDriver?
To find and click the "LOGOUT" text with python, you can use the following code:
logout = driver.find_element_by_xpath("//em[text()='LOGOUT']")
logout.click()
This could help :
Execute button Click with Selenium
As a preach :
You should first, try to analize the general basic components offered for your tool, and the interactions with external systems (selection, executions, listening).
Based on the first link offered as a resource your code should be some like :
package postBlo;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chromse.ChromeDriver;
public class singleClickButton {
public singleClickButton() {
super();
}
public static void main(String[] args) throws Exception {
System.setProperty("webdriver.chrome.driver", "./exefiles/chromedriver.exe");
WebDriver = new ChromeDriver();
driver.manage().window().maximixe();
driver.get("your-local-site-to-test");
//Referen an input component and set a values
driver.findElement(By.name("id-html-tag")).sendKeys("someValue text");
/* ## Execution of button by using id
You could use both methods to identify the element you need :
By using "xpath" expression wich allows you to navigate between elements by using expressions
By using id-identifier
Chose one of both.
driver.findElement(By.xpath("expression-xpath")).click();
driver.findElement(By.id("id-element")).click();
*/
driver.findElement(By.xpath("/html/body/elemnts-container-button/button\r\n" + "")).click();
driver.findElement(By.id("button-id")).click();
}
}
As a mention I'm not related to Selenium but still the logic it's alike.
Best
I'm setting up a Selenium script on IE 11 to interact with checkboxs and radio buttons and am running into errors regarding CSS selectors not being found. I am able to get the script to log me in and navigate to the correct area using other CSS selectors.
Here is the result of Inspect Element on the checkbox that I am trying to work with.
<input name="AltrntProxyInd1" id="AltrntProxyInd" style="display: block; visibility: visible;" onclick="if(this.value != "Y"){ this.value = "Y"; countInstrucType(this, 'AltrntProxy' , 'Y'); } else{ this.value = "N"; countInstrucType(this, 'AltrntProxy' , 'N'); } fnRefreshInstructionGroup(this); if(typeof(fnChangedNotificationFunction) != "undefined") { fnChangedNotificationFunction(this); }" type="checkbox" value="Y" xp2="0" xp1="Instruction" csentry="" cshidden="0" cshiddenorig="0" csentryorig="O" vo="N" CSEntryBeforeHide="O">
When I try and use
browser.find_element_by_id("AltrntProxyInd").send_keys(Keys.SPACE)
I am given the error Unable to find element with css selector == [id="AltrntProxyInd"]
My current workaround is to use the following code, which targets a separate CSS element and then TABs down to the desired element. This is giving me the desired outcome, but I want to eliminate the tabbing and work with the element directly.
browser.find_element_by_id("urlAccountSpecialHandler").send_keys(Keys.TAB * 11)
AltProxyBox = browser.switch_to.active_element
time.sleep(1)
AltProxyBox.send_keys(Keys.SPACE)
Please let me know if a screenshot of the webform would be needed/helpful in diagnosing this issue. Thank you.
Note: I particularly deal with this website
How can I use selenium with Python to get the reviews on this page to sort by 'Most recent'?
What I tried was:
driver.find_element_by_id('sort-order-dropdown').send_keys('Most recent')
from this didn't cause any error but didn't work.
Then I tried
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_id('sort-order-dropdown'))
select.select_by_value('recent')
select.select_by_visible_text('Most recent')
select.select_by_index(1)
I've got: Message: Element <select id="sort-order-dropdown" class="a-native-dropdown" name=""> is not clickable at point (66.18333435058594,843.7999877929688) because another element <span class="a-dropdown-prompt"> obscures it
This one
element = driver.find_element_by_id('sort-order-dropdown')
element.click()
li = driver.find_elements_by_css_selector('#sort-order-dropdown > option:nth-child(2)')
li.click()
from this caused the same error msg
This one from this caused the same error also
Select(driver.find_element_by_id('sort-order-dropdown')).select_by_value('recent').click()
So, I'm curious to know if there is any way that I can select the reviews to sort from the most recent first.
Thank you
This worked for me using Java:
#Test
public void amazonTest() throws InterruptedException {
String URL = "https://www.amazon.com/Harry-Potter-Slytherin-Wall-Banner/product-reviews/B01GVT5KR6/ref=cm_cr_dp_d_show_all_top?ie=UTF8&reviewerType=all_reviews";
String menuSelector = ".a-dropdown-prompt";
String menuItemSelector = ".a-dropdown-common .a-dropdown-item";
driver.get(URL);
Thread.sleep(2000);
WebElement menu = driver.findElement(By.cssSelector(menuSelector));
menu.click();
List<WebElement> menuItem = driver.findElements(By.cssSelector(menuItemSelector));
menuItem.get(1).click();
}
You can reuse the element names and follow a similar path using Python.
The key points here are:
Click on the menu itself
Click on the second menu item
It is a better practice not to hard-code the item number but actually read the item names and select the correct one so it works even if the menu changes. This is just a note for future improvement.
EDIT
This is how the same can be done in Python.
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
URL = "https://www.amazon.com/Harry-Potter-Slytherin-Wall-Banner/product-reviews/B01GVT5KR6/ref=cm_cr_dp_d_show_all_top?ie=UTF8&reviewerType=all_reviews";
menuSelector = ".a-dropdown-prompt";
menuItemSelector = ".a-dropdown-common .a-dropdown-item";
driver = webdriver.Chrome()
driver.get(URL)
elem = driver.find_element_by_css_selector(menuSelector)
elem.click()
time.sleep(1)
elemItems = []
elemItems = driver.find_elements_by_css_selector(menuItemSelector)
elemItems[1].click()
time.sleep(5)
driver.close()
Just to keep in mind, css selectors are a better alternative to xpath as they are much faster, more robust and easier to read and change.
This is the simplified version of what I did to get the reviews sorted from the most recent ones. As "Eugene S" said above, the key point is to click on the button itself and select/click the desired item from the list. However, my Python code use XPath instead of selector.
# click on "Top rated" button
driver.find_element_by_xpath('//*[#id="a-autoid-4-announce"]').click()
# this one select the "Most recent"
driver.find_element_by_xpath('//*[#id="sort-order-dropdown_1"]').click()
Using this link I want all reviews from that page.
I have used xpaths(given in sample code) to click load more until it disappear from that page,but my solution fails and giving following errors.
Error- Message: Element is no longer attached to the DOM Stacktrace
or
in _read_status
raise BadStatusLine(line)
httplib.BadStatusLine: ''
Sample Code with xpaths
Either
driver.execute_script('$("div.load-more").click();')
or
xpath_content='//div[#class = "load-more"]'
driver.find_element_by_xpath(xpath_content).click()
Is there any solution which may not fail in any case? How can I click on load more until it disappear form that page or Is there any other way to get all reviews from this page?
One more thing I am using firepath to generate review's xpath which is .//*[#id='reviews-container']/div1/div[3]/div1/div/div/div[3]/div/div1/div
Is there a way to get our own xpath instead using firepath?
This is a java solution for your problem. You can use the same logic for python as well
public static void loadAll(WebDriver driver) {
while (true) {
//Using findElements to get list of elements so that it wont throw exception if element is not present
List<WebElement> elements = driver.findElements(By.xpath("//div[#class='load-more']"));
//If the size is zero that means load more element is not present so breaking the loop
if (elements.isEmpty()) {
break;
}
//Assigning first element to a variable
WebElement loadEl = elements.get(0);
//Getting text of element
String text = loadEl.getText().toLowerCase();
//check if text contains load more, as, if it is loading it will have ... ,so we cant click at that time
if (text.contains("load more")) {
loadEl.click();
}
//if text contains 1 to 4 means [for ex "Load More 4"] this is the last click so breaking the loop
if (text.matches("load more [1-4]")) {
break;
}
}
System.out.println("Done");
}
I'm writing a test script using selenium in python. I have a web-page containing a tree-view object like this:
I want to traverse over the menu to go to the desired directory. Respective HTML code for plus/minus indications is this:
<a onclick="changeTree('tree', 'close.gif', 'open.gif');">
<img id="someid" src="open.gif" />
</a>
The src attribute of the image can be either open.gif or close.gif.
I can detect weather there is a plus or minus by simply checking the src attribute of the img tag. I can also easily access to the parent tag, a, by using .find_element_by_xpath("..").
The problem is that I can't perform the click action not on the img nor the a tag.
I'v tried webdriver.Actions(driver).move_to_element(el).click().perform(); but it did not work.
I think I should mention that there is no problem in accessing the elements, since I can print all their attributes; I just can't perform actions on them. Any help?
EDIT 1:
Here's the js code for collapsing and expanding the tree:
function changeTree(tree, image1, image2) {
if (!isTreeviewLocked(tree)) {
var image = document.getElementById("treeViewImage" + tree);
if (image.src.indexOf(image1)!=-1) {
image.src = image2;
} else {
image.src = image1;
}
if (document.getElementById("treeView" + tree).innerHTML == "") {
return true;
} else {
changeMenu("treeView" + tree);
return false;
}
} else {
return false;
}
}
EDIT 2:
I Googled for some hours and I found out that there is a problem about triggering the Javascript events and the click action from web-driver. Additionally I have a span tag in my web-page that has an onclick event and I also have this problem on it.
After some tries like .execute_script("changeTree();"), .submit(), etc, I have solved the issue by using the ActionChains class. Now, I can click in all elements that they have java-script events as onclick. The code that I have used is this:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('someURL')
el = driver.find_element_by_id("someid")
webdriver.ActionChains(driver).move_to_element(el).click(el).perform()
I don't know if it occurred just to me or what, but I found out that I should find the element right before the key command; otherwise the script does not perform the action. I think it would be related to staling elements or something like that; anyway, thanks all for their attention.