Program to automate form field entry and result checking of webpage - c#

I am trying to create a program in C# (maybe using WinForms) which will enter a licence number into a form field of a specific website and validate whether or not the licence number is a currently valid licence.
I am unsure as to where to start, as I can't even find the form field id in the source code of the website, and am unsure what technologies the website uses.
Additionally, the purpose of this program will be to enter a list of license numbers and return the names and validation status of each license. Datasource being the website.
Any information on how to go about this would be much appreciated, I am an intermediate C# developer - having mostly worked in ASP.Net, though feel Winforms may be better suited for this project.
Kind Regards

You can use a WebBrowser control:
You can load the page using webBrowser1.Navigate("url of site")
Find elements in page using webBrowser1.Document.GetElementById("buttonid") also you can iterate over HtmlElement of webBrowser1.Document.Body.All and check for example element.GetAttribute("value") == "some vaule" to find it.
Set value for element using element.InnerText ="some value" or element.SetAttribute("value", "some value")
Submit your form by invoking the submit of form or click of its submit button using element.InvokeMember("method")
Example
For example, if you browse google and look at page source, you will see name of search text box is "q" and name of the form that contains the search box is "f", so you can write this codes to automate search.
Create a form with name BrowserSample.
From toolbox, drag a WebBrowser and drop on form.
Hanfdle Load event of form and navigate to google.
Handle DocumentCompleted event of webBrowser1 and find f and find q and set InnerText of q and invoke submit of f. This event fires after the navigation and document load completed.
In a real application add required null checking.
Code:
private void BrowserSample_Load(object sender, EventArgs e)
{
this.webBrowser1.Navigate("https://www.google.com/");
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//Because submitting f causes navigation
//to pervent a loop, we check the url of navigation
//and if it's different from google url, return
if (e.Url.AbsoluteUri != "https://www.google.com/")
return;
var f = this.webBrowser1.Document.Body.All.GetElementsByName("f")
.Cast<HtmlElement>()
.FirstOrDefault();
var q = f.All.GetElementsByName("q")
.Cast<HtmlElement>()
.FirstOrDefault();
q.InnerText = "C# Webbrowser Control";
f.InvokeMember("submit");
}
If you execute the program, it first navigate to google and then shows search result:
In your special case
Since the site loads content using ajax, then you should make a delay in DocumentCompleted:
async void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (e.Url.AbsoluteUri != "https://www.onegov.nsw.gov.au/PublicRegister/#/publicregister/search/Security")
return;
await Task.Delay(5000);
var f = this.webBrowser1.Document.Body.All.GetElementsByName("searchForm")
.Cast<HtmlElement>()
.FirstOrDefault();
var q = f.All.GetElementsByName("searchText")
.Cast<HtmlElement>()
.FirstOrDefault();
q.InnerText = "123456789";
f.InvokeMember("submit");
}
Don't forget to add using System.Threading.Tasks; or if you use .Net 4.0 you simple can use System.Threading.Thread.Sleep(5000) and remove async/await.

It looks like the website uses JSON POSTs. If you have FireFox open Developer -> Network and look at the "PerformSearch" entry. That will tell you everything you need to know as far as what the website is expecting in a POST request so you can read the response.

Related

Textbox Locks up

I'm using Visual Studio 2015 - ASP DOTNET C# and WebForms
I've written a program and part of it requires the user to input a number via a textbox, when the user tabs out the event fires successfully and retrieves the record populating all relevant fields on the form.
Sometimes the user can input another number and it fires, on occasion the textbox locks up as if the read only is true, it won't allow you to delete the text, input further text etc, you have to click a random button on the page which then clears the issue. I'm pretty stumped as to why it's doing this.
protected void txtAsset_TextChanged(object sender, EventArgs e)
{
//Validate text input
lblSuccessful.Text = string.Empty;
txtAsset.Focus();
string input = txtAsset.Text;
if (!Regex.IsMatch(input, #"^[0-9]\d*"))
{
lblSuccessful.CssClass = "ErrorMessage";
lblSuccessful.Text = "You have input invalid criteria";
txtAsset.Text = string.Empty;
txtAsset.Focus();
}
else
{
Execute Retrieval of record code
}
}
Many thanks for your help
Because of PostBack in asp.net WebForms.
You have two options:
Check validation in client side with jquery.
put your controllers in UpdatePanel.

how to display full Url in web browser control properly in C#?

I can display the Url in the searchbar. However, it picks up javascript and other loading processes as URL and displays them and doesn't display a conventional Url (e.g https://stackoverflow.com/questions) that we would see in any common browser. So if I search http://www.stackoverflow.com, I get https://ssum-sec.casalemedia.com/usermatch?s=183712&cb=https://engine.adzerk.net/udb/22/sync/i.gif?partnerId=1&userId=. Any help would be appreciated.
private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
player.SoundLocation = "safepage.wav";
player.Play();
if (SearchBar.Text != e.Url.ToString()) //Displays the full Webpage address within the textbox
{
SearchBar.Text = e.Url.ToString();
}
}
Navigation events of web browser control will raise for iframes of the page too. So in this case, what you are getting as result is address of an iframe in the page.
You can use webBrowser1.Url.ToString() instead of e.Url.ToString().
Note: As far as I know, there should not be an iframe in stackoverflow questions page, so itt seems your browser has been infected.
In the _Navigated event, you can use the WebBrowser.Url property. It will get updated each time but not for the redirects like for those tracking/ad scripts.

How to set value of a textfield using C# / IHTMLDocument2

I am a hobbyist programmer and want to do the following:
Log into a site via Username - / Password
Click an image which directs me to a certain (sub)site
Fill out a form
BEFORE submitting the form, I want to Load the whole page and see the content of the input provided by my application before submitting it.
I wrote several Web-scrapers / Parsers in the last few months (All in Java) but now I am facing quite some difficulties with C# and .NET.
I am using Visual Studio 2015 IDE and I do NOT want - if possible - to use 3rd party tools / plugins etc. (if possible, please try to not provide answers hinting at HtmlAgilityPack, JSoup.. equivalents or others). Everything Core to .NET (or just C# in general) etc. is good though.
(1) and (2) do already work, I can log in supplying username and password, and then click() on the picture and get redirected to the form using the SAME code as below.
I have the following Code at the moment: (CAVE: It is a WPF project (NOT WINFORMS), using IHTMLDocument (2)
Currently my Code looks like the following:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
using mshtml;
using System.Diagnostics;
public partial class MainWindow : Window
{
private CustomObject testObject;
public IHTMLDocument2 doc2;
public MainWindow()
{
InitializeComponent();
Browser.Navigate("https://www.xXx.xXx/"); //The Browser is the standard WPF WebBrowser
// Several other functions like LoadComplete etc. here
}
// Function for login
private void Browser_Login(object sender, RoutedEventArgs e)
{
doc2.all.item("ID_OF_USERNAME_TEXTFIELD").value = "MyUsername";
doc2.all.item("ID_OF_PASSWORD_TEXTFIELD").value = "MyPassWord";
doc2.all.item("NAME_OF_SUBMIT_BUTTON").click();
}
private void Browser_ClickOnImageLinkToGetToForm(object sender, RoutedEventArgs e)
{
// Logic to get to the Form, everything works as expected
}
private void Browser_FillForm(object sender, RoutedEventArgs e)
{
doc2.all.item("NAME_OF_THE_TEXTFIELD_TO_FILL").value = "Text if want to put into the field";
// /repeat for all other TextFields and a couple of other input elements.
--> Exception!
}
Every time I run the code I do the following:
Start application --> WebBrowser opens, directs me to the homepage.
Click Button1 (Browser_Login) --> AutoFill username && Password --> click Submit (i am logged in now)
Click Button2 (Browser_ClickOnImageLinkToGetToForm) --> "Click()" on Image, get redirected to the form.
Click Button3 (Browser_FillForm) --> RunTimeException:
Additional information: 'System.__ComObject' does not contain a definition for 'textContent' OR definition for 'value' OR definition for 'innerText' OR definition for 'InnerHtml' etc..
I have tried A LOT of different things, none seem to work.
The TextField i want to fill has the following properties:
<input class="TxtField1" maxlength="800" type="text" id="Title" name="Title" value="" onkeyup="checkField(this.name);" onblur="checkField(this.name);" style="width: 550px; cursor: help; background-color: rgb(228, 234, 224);" title="Some Title">
I have never encountered such problems coding in Java, also some people mention I should check for 32 / 64 bit systems and some suggested to write a Wrapper for the_COM object and some other things. I don't want to write a Wrapper tough, nor do i want to check for 32 -/ 64 -bit, i want to run it on every system.
Would someone provide a simple standard .Net / C# solution for this? Please keep in mind, I am a hobbyist, I am NOT a professional developer (Maybe if won't understand some super in-depth examples (I'll most definitely learn them tough)).
TL;DR:
How to Fill a Form which checks content on keyup with WPF WebBrowser control using .NET / C#!
There are a lot of things you can do if you get hold of the DOM like this:
private dynamic GetDOM(WebBrowser wb)
{
dynamic document = null;
System.Threading.Thread.Sleep(500);
while (document == null)
{
Dispatcher.Invoke(() => document = wb.Document);
System.Threading.Thread.Sleep(100);
}
return document;
}
Not sure why what you were doing wasn't working, but I copied this code from a working solution. You can cut out the Dispatcher stuff if you are on the main thread.
You get a COM object that has a lot of methods just like in JavaScript. So to set the text you can do something like this:
document.getElementById("bob").value = "fred";

How to do multiple actions in WebBrowser_DocumentCompleted in c#

So, I'm creating a bot using webBrowser in c# that loads a website entered in the text box. When the website is loaded, I need bot to click on a specific anchor text. After that when a new page is loaded, I need to click on another anchor text and so on, until a form to fill out details appears. I also need to show captcha to the user where he/she can fill it and submit it, so that the page can continue to next page.
What I need is to invoke different methods, each time the browser navigated to next page and loading is complete. I have successfully created a WebBrowser_DocumentCompleted, but it get invoked over and over again, due to the fact that same hyper link is present on the page that I want to visit. But, on that page I need to click on a button.
I did this for getting the link and visiting it.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Select the html element by inner text of anchor and click on it
HtmlElementCollection elc = this.webBrowser1.Document.GetElementsByTagName("a");
foreach (HtmlElement el in elc)
{
if (el.InnerText == null || el.InnerText.Equals("Matching text"))
{
el.InvokeMember("click");
}
}
}
After this the link that have matched innretext get clicked and the page loads. The page have same anchor text and it gets loaded again and again. But, I need to click on another button and go to next page.
So, if you have any way that I can use to do it then it would be awesome.Any help is welcomed!
P.S. I'm a beginner in C# and .net
The behaviour you see is normal, I suppose the page you are loading has some iframes or embedded content and for each one loaded the DocumentCompleted will be fired (it's not related on having a link to the page, a link does nothing until it's clicked).
You must take actions based on the Url parameter of the WebBrowserDocumentCompletedEventArgs passed on thos function, in this way you can execute the required action for each concrete page, something like this:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
switch(e.Url.ToString())
{
case "http://myfakeserver.com/mypageone.htm":
//Do whetever you want to do
break;
case "http://myfakeserver.com/mypagetwo.htm":
//Do more stuff
break;
}
}
Hope it helps.
EDIT:
Ok, now I get what you need.
It's easy, just check if you area already on that page.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Select the html element by inner text of anchor and click on it
HtmlElementCollection elc = this.webBrowser1.Document.GetElementsByTagName("a");
foreach (HtmlElement el in elc)
{
var hRef = el.GetAttribute("href");
if(string.IsNullOrWhitespace(hRef))
continue;
var lnkUri = new Uri(hRef);
//If the link points to this page, ignore it
if(lnkUri.Segments[lnkUri.Segments.Length - 1] == e.Url.Segments[e.Url.Segments.Length - 1])
continue;
if ((el.InnerText == null || el.InnerText.Equals("Matching text"))
{
el.InvokeMember("click");
}
}
}
Beware in the example i'm just checking the last part of the url, so if you have different paths which have the same page name it will fail, you must adapt it to your needs, depending on how the uris are written on the href you can do a full check of the urls.

Wait till the GeckoFX Webbrowser has loaded

I want to automate a few tasks on my website with GeckoFX for some testing.
That should happen when I click a button and everything should be automated after that button click.
This includes clicking buttons where the page refreshes so the code has to wait till the page has loaded and that's where my problem is.
If I do it like that:
geckoWebBrowser1.Navigate("http://mywebsite.com");
GeckoInputElement searchText = new GeckoInputElement(geckoWebBrowser1.Document.GetElementsByName("searchbox")[0].DomObject);
searchText.Value = "GeckoFx";
I get an error, so how can I put it that the code after .Navigate waits till the webbrowser has fully loaded the page?
You can use DocumentCompleted Method to perform your automatic operations.
private void geckoWebBrowser1_DocumentCompleted(object sender,EventArgs e)
{
// Here you can add the coding to perform after document loaded
}
For example : First initiate the browser to google page by geckoWebBrowser1.Navigate("https://www.google.com");
After google page loaded you can do the following in document_completed method:
GeckoInputElement search =new GeckoInputElement(geckoWebBrowser2.Document.GetElementsByName("q")[0].DomObject);
GeckoInputElement button = new GeckoInputElement(geckoWebBrowser2.Document.GetElementsByName("btnG")[0].DomObject);
search.focus();
search.Value = "Master Blaster Sachin";
button.Click();
so it will search the value you given automatically after the google page loaded. Like that you can modify the program as per your logic. Hope it helps..
I would go an use a product like Selenium http://seleniumhq.org/. It's free open source web testing which is scriptable.

Categories

Resources