dotnetcsharp

POST Data with .net Html Agility Pack

Extension methods for the Html Agility Pack HtmlWeb class to handle form submissions with POST data.

I’m using the Html Agility Pack for getting and parsing HTML pages. It offers many possibilities, including XPath selectors.

Today I had a problem with posting data to a webpage. It’s possible to call the HtmlWeb Load function with a second “POST” parameter, but it offers no easy way to add values to be posted.

After a while of searching I came across this solution: add this two functions to the HtmlWeb class. (You can get the source in download section, too)

public HtmlDocument SubmitFormValues (NameValueCollection fv, string url)
{
    // Attach a temporary delegate to handle attaching
    // the post back data
    PreRequestHandler handler = delegate(HttpWebRequest request) {
        string payload = this.AssemblePostPayload (fv);
            byte[] buff = Encoding.ASCII.GetBytes (payload.ToCharArray ());
            request.ContentLength = buff.Length;
            request.ContentType = "application/x-www-form-urlencoded";
            System.IO.Stream reqStream = request.GetRequestStream ();
            reqStream.Write (buff, 0, buff.Length);
            return true;
    }
    this.PreRequest += handler;
    HtmlDocument doc = this.Load (url, "POST");
    this.PreRequest -= handler;
    return doc;
}

private string AssemblePostPayload (NameValueCollection fv)
{
    StringBuilder sb = new StringBuilder ();
    foreach (String key in fv.AllKeys) {
        sb.Append ("&" + Uri.EscapeDataString(key) + "=" + Uri.EscapeDataString(fv.Get(key)));
    }
    return sb.ToString ().Substring (1);
}

Source: http://htmlagilitypack.codeplex.com/Thread/View.aspx?ThreadId=14255

Now posting is easy. Example:

NameValueCollection postData = new NameValueCollection (1);
postData.Add ("name", "value");
doc = this.hw.SubmitFormValues (postData, url);

(hw is an HtmlWeb object and doc an HtmlDocument object)

If you need to use cookies, too, you need to modify the HtmlWeb a little more, because there is a little bug. First add a new private variable:

private CookieContainer _ck = new CookieContainer();

Then find this section:

if (_useCookies)
{
        req.CookieContainer = new CookieContainer();
}

And change it into:

if (_useCookies)
{
        req.CookieContainer = this._ck;
}

Now you just have to activate the usage of cookies in your HtmlWeb object:

this.hw = new HtmlWeb ();
this.hw.UseCookies = true;

That’s it! Enjoy easy form posting with a full cookie jar (: