Selenium, pop up form (Python) - javascript

I am trying to fill forms on certain webpages. I am having success with most
pages however certain ones are giving me trouble.
Some pages have a format where the form is not initially visible on the page itself, instead you need to click a button which then opens a (what seems to be JavaScript) pop up within the page which then needs to be filled.
I have looked around and have seen examples which address how to fill forms which get created in a new pop up window and which get created in alert windows. However I can not seem to find any examples which can solve this particular case.
This is the code I have so far.
driver = webdriver.Chrome()
driver.implicitly_wait(10)
mouse = webdriver.ActionChains(driver)
driver.get(url)
driver.maximize_window()
value = 'fill form'
span_xpath = '//span[contains(text(), "' + value + '")]'
span_element = driver.find_element_by_xpath(span_xpath)
mouse.move_to_element(span_element).click().perform()
time.sleep(5)
Everything works till here, the fill form button gets clicked which opens the form in the browser page.
But when the following is execute an error always arises: "no such element: unable to locate element"
n =driver.find_element_by_id('name')
n.send_keys('john smith')
I have tried to locate the element by, name, id, xpath and so on but no matter what try, it can not locate any of the form elements.
I would greatly appreciate any help on this matter.

First switch using driver.switch_to_frame(0) (parent iFrame)
then switch using driver.switch_to_frame(1) (chiled iFrame)
and then find the element.
Note: instead of using index you can identify the frame using id, name, xpath etc. like any other Web Element and pass that element to switch_to_frame as an argument. This gives more consistency.

Related

Trying to programatically click a button on a web page with cefsharp

I'm using cefsharp and vb.net to put some code together to move to the next page of this site:
https://www.recommendedagencies.com/search#{}
The idea is to read the list of company names on each page and store to a csv file. This part I can do.
The problem I have is that I can't find the name of the 'Next' button - presumably if I had that I could execute some javascript on the browser to press the button.
I've inspected the page in Firefox, but can't see any name I can use - I'm not really familiar enough with html/page design to know why not or how it works.
Could anyone tell me a good method to get button names from a web page? - I've done some searching and even asked a similar question myself before, but I can't find anything which helps, given my patchy knowledge.
Thanks
Inspect the DOM for the 'Next' button.
Look for id's or classes that you can use to identify it.
use document.querySelector() to find the element by the css selector
call the element.click() function to programatically press next
const nextButton = document.querySelector('.sp-pages-nav_next')
nextButton.addEventListener('click', (event) => {
console.log('something clicked next')
})
nextButton.click()
<div class="sp-pages-nav sp-pages-nav_next" data-reactid=".1.3.4.1">Next</div>
In the above snippet on load you can see the code nextButton.click() invokes the console log. You can click the word Next manually to the same effect.
in cefsharp perhaps something like:
browser.ExecuteJavaScriptAsync("(function(){ document.querySelector('.sp-pages-nav_next').click(); })();");
A very similar example can be found here :
https://github.com/cefsharp/CefSharp/wiki/General-Usage#1-how-do-you-call-a-javascript-method-from-net
// When executing multiple statements, group them together in an IIFE
// https://developer.mozilla.org/en-US/docs/Glossary/IIFE
// For Google.com pre-populate the search text box and click the search button
browser.ExecuteJavaScriptAsync("(function(){ document.getElementsByName('q')[0].value = 'CefSharp Was Here!'; document.getElementsByName('btnK')[0].click(); })();");

Selenium doesn't click on the top-most element

Consider the following Selenium automation:
Its goal is to go to a financial chart from the website Barchart, click on the custom calendar icon (at the top right corner over the chart), input a custom range in the form that pops up over it, and validated it using the apply button.
driver = webdriver.Chrome()
url = 'https://www.barchart.com/stocks/quotes/AAPL/interactive-chart'
driver.get(url)
driver.find_element_by_css_selector('.calendar-icon').click()
driver.find_element_by_css_selector('option[label="Intraday"]').click()
driver.find_element_by_css_selector('[data-ng-model="selectedAggregation.range.from"]').send_keys('11/01/2019')
driver.find_element_by_css_selector('[data-ng model="selectedAggregation.range.to"]').send_keys('11/01/2019')
driver.find_element_by_css_selector('[data-ng-model="selectedAggregation.range.to"]').send_keys(Keys.ENTER)
driver.find_element_by_css_selector('[data-ng-click="modalConfirm()"]').click()
It works fine for the most part, until I try to validate, which never works. I then realised that sometime this last action would lead me to a promotional page whose link is located exactly beneath the Apply button. Which seems to indicate that selenium 'click through' the form onto the link below.
I have tried other selector for the apply button, which all give the same result.
I also try to use the submit() method from selenium, which returns an error. Lastly, I also try to implement the execute_script method from selenium, but I did not manage to understand what exactly is the javascript call being executed on clicking apply.
Note : this is because i need to get the cookie and xsrf token that is generated by that call, not because i need to collect the actual financial data ( I know that the financial data can be collected using 'https://www.barchart.com/proxies/timeseries/queryminutes.ashx?' + data), where data are the query string parameters.
Any help greatly appreciated.
I had a look for you, the below should accept the changes for you, I've checked this and it works for me.
javascript = 'document.querySelector("body > div.reveal-modal.fade.interactive-chart-modal-aggregation.in > div > div > div > button.bc-button.light-blue").click()'
driver.execute_script(javascript)

Using VBA in automating data scraping as well as pressing buttons inside a multi-framed intranet webpage

I am trying to put a value in a textbox that is within a frame of a company intranet webpage .aspx and extract data depending on the value inputted in the textbox. Nothing seems to work, I have tried clicking and changing the dropwdownlist within the login screen using this code IE.document.getElementsByTagName("select")(1).Value = "optionvalue" this works. I was able to automatically login in the webpage so I know that `getElements works but after logging in it apparently does not detect the elements in the webpage such as the textbox and dropdownlists.
Today I found out that the cause of this is because of the multi-frames within the webpage I tried on viewing the source and apparently it is divided to three frames Banner, CSLeftFrame and CSMainFrame.
This is my current code
Dim IE As InternetExplorerMedium
Dim objCollection As Object
________________________________________________________________________________
Private Sub AccesLoginLink()
Set IE = New InternetExplorerMedium
IE.navigate "Https://website.aspx"
IE.visible = true
PageLoadStart
End Sub
________________________________________________________________________________
Private Sub automatereview_click()
If IE Is Nothing Then Set IE = New InternetExplorerMedium
IE.navigate "Https://framewebsite.aspx"
IE.Visible = True
PageLoadStart
IE.document.getElementByTagName("select")(0).Value = "Option in a dropdown"
________________________________________________________________________________
Private Sub PageLoadStart
While IE.Busy Or IE.readyState <> 4: DoEvents: Wend
End Sub
What I did in the code above was access banner frame link that I saw in the view source and that is where I navigated and changed the dropdownoption for testing it apparently worked but what happened was the BannerFrame was the only frame that loaded. Is there a way to Click buttons or input a value in a textbox or scrape data within a frame?
The reason I am having a hard time is because I am confused as to when I do inspect element in my understanding the textbox is in the body of a body class leftframe in the frame which has the same frame name and Id of someLeftPage and the source is the CSLeftFrame which is in an iframe which has a name, id, class and source inside the form which has a name, id, action and method which is all inside the frame in the name of contentframe which has a name,id,src.
Here is the pictures for the HTML codes to make it easier for you I highlighted the element tags for the textbox and dropdownlist. and below here are the inspect element codes for the page.
The SearchBar and Button to click is within the form id that its action = CSLeftFrame.aspx** within the body class LeftFrame which all of them is inside the iFrame Which all of the mentioned above is all inside a Form that its action = content.aspx and inside the frame name called ContentFrame.
IE.Document.GetElementById("ctlsearch_ddlSearchOptions").value = "NNum" '<----change this to what ever value that is listed.
IE.Document.GetElementById("ctlsearch_ddlSearchOptions").FireEvent ("onchange")
Sleep (2000) '<---- I use a way to pause the script because it can sometimes take so time fot the onchange event to take effect.
SearchText = "The text that I am seaching for" '<----change this to the text you are searching for.
IE.Document.GetElementById("ctlSearch_txtfind").value = SearchText
It's hard to tell without seeing everything if there is multiple frames/tables/forms. So these do not include any sort of hierarchy. If there is you would need to include a getElementByid() or a getElementsByTagName()(0) after the .Document.

Selenium WebDriver: clicking a visible button inside a row of a table

My apology as this question is quite long.
To be more specific, I am trying to click on the Pencil icon (Edit button) that is shown on the 4th row
Here's the code I tried to execute:
WebElement ele = driver.findElement(By.xpath("//a[contains(#title, 'Edit Row')]"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
Executor1.executeScript("arguments[0].click();", ele);
And here's the HTML code
After I ran the selenium code, the driver actually clicked on the Edit button of the 1st row (Administration | NA) instead of the 4th. I found out that not only the 1st but other rows also have the same HTML code, only difference was that the Pencil/Edit button is hidden because I wasn't the one that created the values of that row.
I did try with the following code as well:
driver.findElement(By.xpath("//a[contains(#title, 'Edit Row')]")).click();
I then received the error
element is not currently visible and so may not be interacted with
It seems the driver was still looking at the hidden Edit button in the first row, instead of the obvious visible one in 4th.
Is there anyway that I could click on the Edit button based on the value instead of the row number? The reason is that in the future, the value I enter for testing may not end up in 4th but 1st or 10th row.
Last but not least, my Safari can't seem to run the JS Executor code, everytime I gave it a go, the following error returned:
org.openqa.selenium.WebDriverException: 'undefined' is not a function (WARNING: The server did not provide any stacktrace information)
Can someone shed some light on this for me as well?
Cheers
Since there is only one edit icon displayed, the code below should work.
driver.findElement(By.cssSelector("a[title='Edit Row']")).click();
I think the reason you were running into the hidden element issue is that you were using JSE to click on it. Selenium is designed to only interact with elements that are visible... the way a user would. JSE allows you to interact with elements that are NOT visible. There are reasons to use JSE but I don't believe this is one of them. Using JSE you were finding an element that matched your XPath that was not visible and then trying to click on it... thus the error.
I suggest you to go once in firefox and then try same xpath in firebug with firepath add-on.
Try to inspect xpath of the pencil icon. Only one maching element with no dynamic values in that, then you can and use it. Else evaluate this xapth
//a[contains(#title, 'Edit Row')]
You can find one or more matching elements. Then try to find difference in one of attribute for required element. If you are able to create xpath by using that odd attribute then its on else go for List and in loop cross theck for that, then work on it.
Thanks murali and JeffC for the suggestions, I have managed to get the driver to click on the displayed Pencil with this:
List<WebElement> EditButtons = driver.findElements(By.cssSelector("a[title='Edit Row']"));
for(WebElement button : EditButtons) {
if(button.isDisplayed()) {
button.click();
}
}
Although it only solved half of the issue, I am trying to click on the displayed Edit button based on the value next to it. If I create another row with the value of 'Test234' and if the row is placed under the 4th row, the Edit button of 'Test234' won't be clicked. Any suggestion? I tried this but it doesn't seem to work, driver still clicked on the first visible edit button it saw:
List<WebElement> EditButtons = driver.findElements(By.cssSelector("a[title='Edit Row']"));
String textvalue = driver.findElement(By.xpath("//span[contains(text(),'test456')]")).getText();
for(WebElement button : EditButtons) {
if(button.isDisplayed() && textvalue.equalsIgnoreCase("test456")) {
button.click();
}
}
UPDATE: Alright, issue resolved, I switched back to use xpath instead of cssSelector, then modified Vagnesh's suggestion (Thanks Vagnesh !!) a bit and now the driver is clicking on the visible edit button next to the text I search for without going through the loop
driver.findElement(By.xpath("//span[contains(text(), 'Enter my desired Text here')]/following::div//a[contains(#title,'Edit Row')]")).click();
You should find the element based on the field text, so that it can find its corresponding edit link.
functional_area = "Business Development / Innovation"
WebElement ele = driver.findElement(By.xpath("//span[#class='xspTextComputedField'][contains(#text, '" + functional_area + "')]/following-sibling::div/a[contains(#title, 'Edit Row')]"));
You can make it more dynamic by parameterizing the text ex. Financial.

Dynamic Confirmation Message on a confirm.html

I am trying to create a Javascript function to display a dynamic confirmation message, that will appear on a confirm.html page. It needs to be in an external Javascript file so that it can be used on a variety of pages. I've tried a variety of things but I just cant quite get it to work correctly. I'm trying to do it with only Javascript.
This is what I have currently, after doing some research
This is button I'm using to call the function
<input type="button" value="Remove" onclick="dynamicMessage('This product has been deleted')">
and the current function I'm using is
function dynamicMessage(argument)
{
var test = window.open("./confirm.html","_self");
test.document.write("test");
test.document.close();
}
Obviously, the dynamic content isn't added in yet, but if my thinking is correct, it should just be adding the argument somewhere in the long string of html I need to add to create the page. The "test is just do see what happens when calling the function.
What I want it to do is, write the "test" to the new window of confirm.html, but instead it overwrites the current window. But if I only call window.open, it opens to the correct window. It is the document.write part that is throwing me off.
I'm not sure if I'm far off base on my thinking, or if its just a simple mistake I'm missing after hours of looking at this code. Any Ideas?
I think I need to clarify what I am trying to do. I am trying to click a button, in this case a remove button, then open up the page confirm.html, edit the content in confirm.html with the argument, and have the current page now be confirm.html. What currently happens is one of two things either the current document is edited if the "_self" tag is placed, or the html page is open and thus an about_blank url.
Hope i understood your question | DEMO
Since you are using document.write method it will overwrite contents of your html page
function dynamicMessage(argument)
{
var test = window.open("./confirm.html","_blank");
test.document.write(argument);
setTimeout(function(){test.close()},2000); // after 2 sec it will close
}

Categories

Resources