1
votes

On a website: http://www.e-korepetycje.net/ there is form which is used to log in:

<form method="post" action="http://www.e-korepetycje.net/zaloguj" id="login-box">
   <fieldset>
      <ul>
         <li><input type="text" name="login" placeholder="Login or email"></li>
         <li><input type="password" name="passwd" placeholder="Password"></li>
         <li><input type="submit" value="Log in"></li>
      </ul>
   </fieldset>
</form>

I woule like to fill input field login and passwd and then submit this form programatically by C#.

I have seen THIS TOPIC, but the most upvoted answer is just somebodies code which does not refer to the HTML posted in question and there is no HTML to which response refer to so it is hard to understand


UPDATE

I have used Adriano Repetti's answer. I get exception here var inputField = Descendants(form).First(x => x.GetAttribute("name") == "login"); sequence does not contain specified element (InvalidOperationException).

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;

namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); WebBrowser wb = new System.Windows.Forms.WebBrowser(); wb.DocumentCompleted += wb_DocumentCompleted; wb.Navigate("http://www.e-korepetycje.net/"); Console.WriteLine("After navigate"); } public static IEnumerable Descendants( HtmlElement root) { foreach (HtmlElement child in root.Children) { yield return child;

            if (!child.CanHaveChildren)
                continue;

            foreach (var subChild in Descendants(child))
                yield return child;
        }
    }

    static void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {

        WebBrowser wb = ((WebBrowser)sender);
        if (e.Url.AbsolutePath == (sender as WebBrowser).Url.AbsolutePath) {
            Console.WriteLine("COMPLETED");
            //HtmlElementCollection elems = wb.Document.GetElementsByTagName("HTML");
            //Console.WriteLine(elems[0].OuterHtml);
            var form = wb.Document.GetElementById("login-box");
            Console.WriteLine(Descendants(form).Count());


            var inputField = Descendants(form).First(x => x.GetAttribute("name") == "login");
            inputField.SetAttribute("value", "login");

            inputField = Descendants(form).First(x => x.GetAttribute("name") == "passwd");
            inputField.SetAttribute("value", "passwd");

            var submitButton = Descendants(form).First(x => x.TagName == "input" && x.GetAttribute("type") == "submit");
            submitButton.RaiseEvent("click");
        }


    }
}
}

Output

After navigate
'WindowsFormsApplication1.vshost.exe' (CLR v4.0.30319: WindowsFormsApplication1.vshost.exe): Loaded 'C:\Windows\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll'. Module was built without symbols.
COMPLETED
'WindowsFormsApplication1.vshost.exe' (CLR v4.0.30319: WindowsFormsApplication1.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core.resources\v4.0_4.0.0.0_pl_b77a5c561934e089\System.Core.resources.dll'. Module was built without symbols.
A first chance exception of type 'System.InvalidOperationException' occurred in System.Core.dll
12
'WindowsFormsApplication1.vshost.exe' (CLR v4.0.30319: WindowsFormsApplication1.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

UPDATE 2

I also tried:

var inputField =  wb.Document.GetElementsByTagName("text")["login"];

but it returns null.

2
@DeeMac Neither, it is console application. The site is not mine I want to fill this form on: e-korepetycje.net and submit it by code.Yoda
Ok, I see. This question is massively misleading - I, at first, assumed you wanted to use C# to perform some sort of client-side functionality typically handled with JS. I would've thought it was a case of making a web request to the server with the relevant credentials being passed in, in which case - isn't that exactly what that answer suggests?user1017882
@DeeMac The answer(in other topic) does not clarify where to use action from the form action="http://www.e-korepetycje.net/zaloguj" also does not clarify are these String strPost = "username="+username+"&password="+password+"&firstname="+firstname+"&lastname="+lastname; are the names of input fields in form etc. The problem is that that author of answer did not post the HTML his code refers to so it is not self explanatory code.Yoda
I believe Adriano has given you a thorough answer. Can I ask (purely out of curiosity) what you're doing with this/why you're doing it?user1017882
@Yoda document is null because download and DOM parsing is not completed. Add your code (to search and fill form) inside DocumentCompleted event (updated answer to make it clear).Adriano Repetti

2 Answers

2
votes

Easiest way to programmatically interact with a web site (from a C# application) IMO is to use WebBrowser control:

WebBrowser wb = new System.Windows.Forms.WebBrowser();
wb.Navigate(" http://www.e-korepetycje.net/");

Now that site has been loaded in the embedded web browser (IE based). You may inject some JavaScript code to perform this task but also from C# is pretty easy. When document downloading and DOM parsing is completed you can go find the form (using its ID). Put all subsequent code in wb.Document.DocumentCompleted event handler (you may also, if you wish so, wait on wb.Document.DocumentStatus property).

var form = wb.Document.GetElementById("login-box");

Then find submit button inside it:

var submitButton = form
    .Descendants()
    .First(x => x.TagName == "input" && x.GetAttribute("type") == "submit");

Then simulate a click:

submitButton.RaiseEvent("click");

I used a small helper function to iterate through all children of a HtmlElement:

public static IEnumerable<HtmlElement> Descendants(this HtmlElement root)
{
    foreach (HtmlElement child in root.Children)
    {
        yield return child;

        if (!child.CanHaveChildren)
            continue;

        foreach (var subChild in Descendants(child))
            yield return child;
    }
}

BTW if you want to inject JavaScript code it has to be simply this (of course you'll need much more code to create the script function with Document.CreateElement() and to invoke it with Document.InvokeScript()):

document.forms["login-box"].submit();

Please note that same technique may be applied to also fill the form:

var inputField = form
    .Descendants()
    .First(x => x.GetAttribute("name") == "login");

inputField.SetAttribute("value", "login name to post");

Of course all this code may be generalized enough to be reused...

0
votes

You can create a windows form, add WebBrowser control to it and then set url to website. After url loaded into the browser control you can access Document property to invoke script (to populate userid and password and submit form) using InvokeScript(script) method.