I have a simple code that help me crawl to page 2 of Google result page:
var ie= new IE();
ie.Link(Find.ByText("2")).Click();
All I want is crawling to more next page with the inputed number of page, so that I make a loop like this:
string[] page = null;
for (int i = 0; i < NumOfPage; i++)
{
Array.Resize<string> (ref page, i+1);
page[i] = "\"" + i.ToString() + "\"";
}
int count=2;
while (count<NumOfPage)
{
ie.Link(Find.ByText(page[count])).Click();
count++;
}
But the result is it pause at the first page, no crawling to the next page. It's seem the loop doesn't work. Where is the problem???
I think you should not use Click() method to go to the next page, I recognized that Click() will be performed only when the Link is visible, so you have to scroll the vertical scrollbar to the bottom to show the Link first (scrolling manually or programmatically works as you want). However I think to go to the next page, you can call the method GoTo() instead with the Url got from the found Link. I've tested it OK but the delay between page switches is a little large (about 2 seconds or above). I don't know why you want to do this and would like to know it from you:
for (int i = 2; i < NumOfPage; i++)
{
ie.GoTo(ie.Link(WatiN.Core.Find.ByText(i.ToString())).Url);//Don't need quotes at all.
}
:)
// Setup browser object
var browser = new IE();
var url = "www.google.com";
browser.GoTo(url);
var searchBox = browser.TextField(Find.ByName("q"));
searchBox.Value="Rex";
//click on the search button
var btnSearch = browser.Button(Find.ByValue("Search"));
btnSearch.Click();
//wait for browser to load properly
browser.WaitForComplete();
// Find the navigation menu table
var navigationtable = browser.Table(Find.ById("nav"));
// To go to the second page
var secondpage = navigationtable.Link(Find.ByText("2"));
secondpage.Click();
//wait for browser to load properly
browser.WaitForComplete();
this simply goes to the second page
now if you want to loop through
then
for (int i = 2; i <= 10; i++)
{
var nextpage = navigationtable.Link(Find.ByText("i"));
//check if the link exists
/if yes then click on it
if(nextpage.Exists)
nextpage.click();
browser.waitforComplete
}
Related
So, i am trying to use Selenium to scrape this webpage that updates every couple seconds. I am looking to click on the most recent link which, in this case, is the link by Edward Researcher. This list will update multiple times and get updated with new links stacking at the top.
My current code basically takes the top most link of the entire page when I want it to take links that are shown on the page starting from the top
allLinks = driver.FindElements(By.XPath("/html/body/div[6]//a")).ToHashSet();
This will get all the clickable links going top down using a tags to grab the links. My problem is trying to only get links from one place on the webpage and grab that link everytime it updates. Not really sure how to do that since the code and xPath changes with every added link. Any help would be greatly appreciated
The bottom most mark in red is the current link that I inspected that is topmost but when the page gets updated with new Links the two top red marks are where they will be updated in another DIV.
The Code that I have a t the moment works to grab the first link on the page but I would prefer to start at the Logged hits section as shown in the first image. Here is the code that makes it work:
public static void searchAllLinks()
{
//HitForker is labelled as '0'
//PandaCrazy tab is labellled as '1'
//Start index at 1
int listIndex = 1;
//Different numbers need for the first run down the list
bool firstRun = true;
//HashSet to store all IWebElements found on page at runtime
HashSet<IWebElement> allLinks;
//Get browser tabs open at current time
var browserTabs = driver.WindowHandles;
//Switch to HF
driver.SwitchTo().Window(driver.WindowHandles[0]);
//Grab links from page starting at Logged Hits Most recent Div
allLinks = driver.FindElements(By.XPath("/html/body/div[6]//a")).ToHashSet();
//Loop through all links in hash
//Hashset contains every link on the page. Only need the middle link to access the content
foreach(IWebElement value in allLinks)
{
if(firstRun == true)
{
//Second link in the hash
if(listIndex == 2)
{
value.Click();
firstRun = false;
listIndex = 0;
whatToClick(value);
}
}
//When linkIndex is 5 then click the value and reset to 0
if(listIndex == 5)
{
value.Click();
whatToClick(value);
listIndex = 0;
}
listIndex++;
}
}
//Method to find which webpage opened on successfull click
public static void whatToClick(IWebElement currentLink)
{
//Grabs the browser handles open
var browserTabs = driver.WindowHandles;
//When the link is clicked on switch to that tab
driver.SwitchTo().Window(driver.WindowHandles[2]);
//2 options
//Hit is not available then add to PC
//Hit is available then accept
try
{
if (driver.FindElement(By.XPath("/html/body/div[3]/div[2]/div/div/div/div[2]/p/span/span/button[2]")).Displayed == true)
{
driver.FindElement(By.XPath("/html/body/div[3]/div[2]/div/div/div/div[2]/p/span/span/button[2]")).Click();
driver.Close();
}
else
{
driver.Close();
driver.SwitchTo().Window(driver.WindowHandles[0]);
}
//Switch Back to the HF
driver.SwitchTo().Window(driver.WindowHandles[0]);
//Catch exception to catch if the hit cannot be accepted
} catch (OpenQA.Selenium.NoSuchElementException e )
{
if (driver.FindElement(By.XPath("/html/body/div[2]/div[1]/nav/div/div[1]/div/div[3]/span/span/button")).Displayed == true)
{
driver.FindElement(By.XPath("/html/body/div[2]/div[1]/nav/div/div[1]/div/div[3]/span/span/button")).Click();
driver.Close();
}
driver.SwitchTo().Window(driver.WindowHandles[0]);
}
catch (OpenQA.Selenium.NoSuchWindowException w)
{
Console.WriteLine("Window Not open");
}
}
Please click the element using relative xpath as follows
driver.FindElement(By.Xpath("//div[#id='log_table']/div[0]/div/div[1]/span[1]//a")).Click()
The above xpath will focus on the first of the table and accesses the hyperlink of that.
QUESTION UPDATE
I am using this piece of code for cor adding multiple labels on button click.
But each and every time it gives count value 0 and after execution only same label comes.
int count = (int)ViewState["count"];
for (int i = 0; i <= count; i++)
{
TextBox txtnew = new TextBox();
txtnew.ID = "label_" + (i + 1);
txtnew.Text = "label_" + (i + 1);
ViewState["count"] = i;
pnlControl.Controls.Add(txtnew);
}
ViewState["count"] = count + 1;
What i want now is how to keep that data of each control binded to it in its more convenient way.
Dynamic controls are lost on every PostBack, so you need to keep track of the created ones somewhere and recreate them when the page is reloaded.
See my anwer here: How to dynamically create ASP.net controls within dynamically created ASP.net controls
It is about buttons but the basic principle is the same. Just replace Button with Label and it will work.
That's cause it's a web application and thus the session is not retained cause web applications are stateless in nature. So, every post back you get a new page instance which will have int count is 0. Solution: Use Session to store the data for future re-use like
int count = pnlControl.Controls.OfType<Label>().ToList().Count;
Session["count"] = count;
Retrieve it back on postback request
if(Session["count"] != null)
count = (int)Session["count"];
I'm newbie in C# and specially in Selenium. The code I'm providing works as intended, but I would like to add to it. Basically how to use Selenium to log into Linkedin, search for CURRENT EMPLOYEES of a company (Walmart for this example) and scrape the links for "send inmail" for every user.... clicking the "next" button on every page until there are no more. The following will open linkedin, login, enter walmart into searchbox, then click the next button.
I would like to write the links found within all the Send InMail buttons to a text file. Inspecting one of the Send InMail buttons gives the following:
<a class="primary-action-button label" href="/requestList?displayProposal=&destID=262919732&creationType=DC&authToken=BrmS&authType=name&trk=vsrp_people_res_pri_act&* amp;trkInfo=VSRPsearchId%3A5225861601486589992400%2CVSRPtargetId%3A262919732%2CVSRPcmpt%3Aprimary">Send InMail</a>
I would like to write all of these links into a text file as it cycles through all the "next" buttons. Also, I would like to know how to select a value from a drop down list that I haven't been able to "inspect" ... When you type "Walmart" or whatever into the search box, a drop-down gives you the option of selecting "people that currently work at walmart", etc. I haven't even been able to inspect that option in developer mode for some reason.
I've updated my code... This now SEEMS to WANT to do what i need...but there seems to be a timing issue where the "next" button might be loading before the "Send InMail" buttons...it will print a few results to the console and clicks next a few times, but then seems to melt down:
// Go to the home page
driver.Navigate().GoToUrl("https://www.linkedin.com");
// Get User Name field, Password field and Login Button
var userNameField = driver.FindElementById("login-email");
var userPasswordField = driver.FindElementById("login-password");
var loginButton = driver.FindElementByXPath("//input[#value='Sign in']");
// Type user name and password
userNameField.SendKeys("me#hotmail.com");
userPasswordField.SendKeys("Password123");
// and click the login button
loginButton.Click();
// perform search
var newSearch = driver.FindElementById("main-search-box");
var searchButton = driver.FindElementByName("search");
// search
newSearch.SendKeys("walmart");
searchButton.Click();
// Get all links from Send InMail buttons
List<IWebElement> elementList = new List<IWebElement>();
elementList.AddRange(driver.FindElements(By.LinkText("Next >")));
if (elementList.Count > 0)
{
foreach(IWebElement item in driver.FindElements(By.LinkText("Send InMail")))
{
Console.WriteLine(item.GetAttribute("href"));
var goForward = driver.FindElementByLinkText("Next >");
goForward.Click();
}
}
Console.ReadLine();
As far as I understand, after you perform search, there will be a search results which will be populated in the list like the ones in the figure attached.
screenshot of the Linkedin search result.
Then iterate through the results using similar method (code sample here is in Java, might be similar in C#)
List<WebElements> results_div = driver.findElemnts(By.xpath("//*[#id="results"]")) // where xpath of the <ul> element
int counter = 2 // because the data starts from id = 2. Refer image.
while(counter <= results_div)
{
WebElement element = driver.findElements(By.xpath("//*[#data-li-position=\"+counter+\"])) //xpath of the <li> element
String anchor_text = element.findElement(By.linkText("Send InMail")).getAtribute("href")
//Write a logic to save the data to a text file
}
Iterate the above until all the results are reached!
Hope it helps.
Edit : Try this, its not a working code! But try it on these grounds. It might help.
#Test(description = "Search the Site with some predefined words after Login and print the href attribute")
public void printUserID()
{
StartPage startPage = new StartPage(driver);
HomePage homePage = startPage.loginIntoAccount(LinkdinAccount.linkedEmail,LinkdinAccount.linkedPassword); // Logs in in to the account
driver.findElement(By.xpath("//*[#id=\"main-search-box\"]")).sendKeys("herbalife");
driver.findElement(By.xpath("//*[#id=\"global-search\"]/fieldset/button")).click();
WebDriverWait wait = new WebDriverWait(driver, 60);
wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//*[#id=\"results\"]"))));
List<WebElement> results_div = driver.findElements(By.xpath("//*[#id=\"results\"]/li")); // where xpath of the <ul> element
System.out.println(results_div.size()); //*[#id="results"]
#driver.findElement(By.xpath("//*[#id=\"results-pagination\"]/ul/li[11]/a")).click();
int count = 1;
wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//*[#id=\"results\"]"))));
while(driver.findElement(By.xpath("//*[#id=\"results-pagination\"]/ul/li[11]/a")).isDisplayed())
{
while(count <= results_div.size())
{
WebElement element = driver.findElement(By.xpath("//*[#data-li-position=\"" + count + "\"]"));
if(element.findElements(By.linkText("Send Inmail")).size() > 0)
{
String anchor_text = element.findElement(By.linkText("Send InMail")).getAttribute("href");
System.out.println(anchor_text);
}
count ++;
}
//for clicking the next button
driver.findElement(By.xpath("//*[#id=\"results-pagination\"]/ul/li[11]/a")).click()
}
I am trying to get an asp.net chart and it's legend to allow me to open up another page in another tab passing the values of the piece of the chart I clicked on with it. I have been able to get it to open up another tab when clicking on the chart by doing the following but it does not pass the data.
Chart2.Series[0].LegendUrl = "chartdetails.aspx";
Chart2.Series[0].Url = "chartdetails.aspx";
Chart2.Series[0].LegendMapAreaAttributes="target=\"_blank\"";
Chart2.Series[0].LegendPostBackValue = "#VALY-#VALX";
Chart2.Series[0].MapAreaAttributes="target=\"_blank\"";
Chart2.Series[0].PostBackValue = "#VALY-#VALX";
If I leave out the urls and mapareaattributes I can then get it to go to the onclick where I am able to get the data, put it in a session variable and use Reponse.Redirect to open the new page where it sees the session variable data,however it doesn't open in another tab, it opens in the same tab.
Chart2.Series[0].LegendPostBackValue = "#VALY-#VALX";
Chart2.Series[0].PostBackValue = "#VALY-#VALX";
protected void Chart2_Click(object sender, ImageMapEventArgs e)
{
HttpContext.Current.Session["VAL"] = e.PostBackValue;
Response.Redirect("chartdetails.aspx", false);
}
How can I get it to do both? Does Response.Redirect have a way to open a new tab? Some research leads me to believe it does not. Is there a way to get both the server side onclick event to run, so I can set the session variable and the chart.series.url to fire after the server side click runs so the session variable would be set before I open the new tab?
I'm feeling like this may be a case of "I can't have my cake and eat it too."
As it turns out I can have my cake and eat it too. If I set the url, postbackvalues, and legendmapareaattributes in my Page_Load and set up the click for the chart to put the PostBackValue in the session variable when you click on the chart it saves the value in the session variable that is listed in the PostBackValue of the Series of the chart. It then opens in a new tab chartdetails.aspx where I can access the information from the session variable.
Chart2.Series[0].LegendUrl = "chartdetails.aspx";
Chart2.Series[0].LabelUrl = "chartdetails.aspx";
Chart2.Series[0].Url = "chartdetails.aspx";
Chart2.Series[0].LegendPostBackValue = "#VALY-#VALX";
Chart2.Series[0].LabelPostBackValue = "#VALY-#VALX";
Chart2.Series[0].PostBackValue = "#VALY-#VALX";
Chart2.Series[0].LegendMapAreaAttributes = "target=\"_blank\"";
Chart2.Series[0].LabelMapAreaAttributes = "target=\"_blank\"";
Chart2.Series[0].MapAreaAttributes="target=\"_blank\"";
protected void Chart2_Click(object sender, ImageMapEventArgs e)
{
HttpContext.Current.Session["VAL"] = e.PostBackValue;
}
I can't use postback to get the value on the series for some reason. So, I want to share my way inspired by #Adam that is loop over the series points after data binding the chart and set URL.
GET:
Series s=new Series("Test");
/*
* After Data bind to the series s
*/
for (int p = 0; p < s.Points.Count; p++)
{
s.Points[p].Url ="test.aspx?name1=value1&name2=value2";
s.Points[p].MapAreaAttributes = "target=\"_blank\"";
}
POST:
(I put javascript function in url. So, It will execute the javascript for me to send a form I created in the function to the text.aspx.)
Series s=new Series("Test");
/*
* After Data bind to the series s
*/
for (int p = 0; p < s.Points.Count; p++)
{
s.Points[p].Url ="javascript:(function(){" +
"var mapForm = document.createElement('form');mapForm.target = '_blank';" +
"mapForm.method = 'POST';mapForm.action = 'test.aspx';" +
"var mapInput = document.createElement('input');mapInput.type = 'hidden';" +
"mapInput.name = 'partID';mapInput.value = 'put any value you need';" +
"mapForm.appendChild(mapInput);document.body.appendChild(mapForm);" +
"mapForm.submit();document.body.removeChild(mapForm);})();";
}
Reference:
Javascript pass values using POST
Ok, I hope I can explain this well enough.
I have one or more third party Up/Down Spinner+Textbox controls on my page that are black boxes that I can't change the source for.
I want the user to change the UpDownControl contents to choose a quantity and then click a calendar button which will:
Add the quantity of all Up/Down boxes.
Call a javascript popup to display a calendar with the count from step 1 in the url "...calendar.asp?qty=5".
My problem is getting the two steps to execute in the same click. As it stands I can click the button once and it counts
the items and adds them to the popup string and then I have to click it a second time to actually execute the JS popup window.
The code was originally written to "load up" the counts into a second button and then programmatically click it but that looks
like a popup to the browsers since the user didn't click that button.
Here is what I have so far that almost works --
On my page:
<asp:ImageButton ID="btnPrepCal" runat="server" Text="PrepCal" OnClick="btnPrepCal_Click" ImageUrl="~/images/Calendar.gif"/>
In code behind:
public void btnPrepCal_Click(object sender, EventArgs e)
{
StringBuilder sbParams = new StringBuilder();
int TotalQty = 0;
int basketItemCount = 0;
int rowIndex = 0;
string Sku = string.Empty;
foreach (GridViewRow varRow in VariantGrid.Rows)
{
int qnty = GetControlValue(varRow, "Quantity", 0);
if (qnty > 0)
{
basketItemCount++;
string optionList = (string)VariantGrid.DataKeys[rowIndex].Value;
ProductVariant variant = _VariantManager.GetVariantFromOptions(optionList);
if (variant != null)
{
BasketItem basketItem = GetBasketItem(optionList, varRow);
if (basketItem != null)
{
TotalQty += basketItem.Quantity;
Sku = variant.Sku;
}
}
}
rowIndex++;
}
if(Sku.Length > 4) Sku = Sku.Substring(0,4);
sbParams.Append(string.Format("?sku={0}&Qty={1}", Sku, TotalQty));
string popup = string.Empty;
popup = string.Format("window.open('http://trustedtours.org/store/egalaxycalendar.asp{0}','Reservation Calendar','width=265,height=465')",sbParams.ToString());
btnPrepCal.OnClientClick = popup;
}
I'm new to .NET and web programming so I'm probably going at it totally backwards so any help is appreciated. I apologize if it's not clear what I'm trying to do or how. If you need any more info please ask - the rest of the file is a lot of shopping cart mumbo jumbo so I left it out, I hope it's enough.
---- update ----
After looking at the referenced pages I get:
Type cstype = this.GetType();
ClientScriptManager cs = Page.ClientScript;
StringBuilder cstext1 = new StringBuilder();
cstext1.Append("<script type=text/javascript>" + popup + "<script>");
cs.RegisterStartupScript(cstype, "PopupCalendar", cstext1.ToString());
And I believe this is added after I set the value of popup near the bottom of my Click handler above, removing the OnClientClick part, right?
Should this popup the other window on a page reload after clicking the button? (I hate being a newb and asking what's probably obvious questions.)
You can accomplish what you're aiming for using the ClientScriptManager.RegisterStartupScript method. Instead of assigning the OnClientClick method of the button to your JS popup code, set that code to run when the page is reloaded using the RegisterStartupScript method.
This page has some good examples: http://dotnetslackers.com/articles/aspnet/JavaScript_with_ASP_NET_2_0_Pages_Part1.aspx
Ken is correct. To add to his answer and clarify why your code was not working - you were assigning the click-handler of your button to do a popup, but only after it was clicked. This is why you only saw the popup after the 2nd click - the handler was not there the first time you clicked it.