HtmlAgilityPack 登录后提交表单

19
我正在尝试使用HtmlAgilityPack登录一个网站(网站:http://html-agility-pack.net)。现在,我无法确定如何去做。我已经尝试通过设置Html表单值来进行操作。
m_HtmlDoc.DocumentNode.SelectSingleNode("//input[@name='EMAIL']").SetAttributeValue("value", "myemail.com");

我随后使用以下代码提交表单:

m_HtmlWeb.Load("http://example.com/", "POST");

然而,这并没有起作用。它没有登录或做任何事情。还有其他人有什么其他的见解吗?

谢谢


有一种简单易行的方法,由Rohit Agarwal和他的BrowserSession类描述得很好。 使用我在这里提到的修复方法,只要将cookies用作会话标识符,它就能正常运行。 - funkypopcorn
请查看我的解决方案,链接如下: https://dev59.com/imYr5IYBdhLWcg3wkbBM#45868450 - eran otzap
3个回答

20
HTML Agility Pack 用于解析 HTML,但不能用于提交表单。你的第一行代码更改了内存中解析的节点。第二行不会将页面提交到服务器 - 它重新加载 DOM,但使用 POST 方法而不是默认的 GET。
看起来你根本不需要在这个时候解析页面,因为你已经知道控件的名称。使用 HttpWebRequest 类向服务器发送一个 post 请求,在请求中包含字符串 email=acb#example.com
以下是我写的一个类似的示例:
/// <summary>
/// Append a url parameter to a string builder, url-encodes the value
/// </summary>
/// <param name="sb"></param>
/// <param name="name"></param>
/// <param name="value"></param>
protected void AppendParameter(StringBuilder sb, string name, string value)
{
    string encodedValue = HttpUtility.UrlEncode(value);
    sb.AppendFormat("{0}={1}&", name, encodedValue);
}

private void SendDataToService()
{
    StringBuilder sb = new StringBuilder();
    AppendParameter(sb, "email", "hello@example.com");

    byte[] byteArray = Encoding.UTF8.GetBytes(sb.ToString());

    string url = "http://example.com/"; //or: check where the form goes

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    //request.Credentials = CredentialCache.DefaultNetworkCredentials; // ??

    using (Stream requestStream = request.GetRequestStream())
    {
        requestStream.Write(byteArray, 0, byteArray.Length);
    }

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    // do something with response
}

2
如果您要下载和解析登录页面之外的页面,您可能需要在后续请求中传递从登录响应中接收到的cookie。有关更多信息,请参见此问题+答案 - Anders Fjeldstad
@Anders - 好的提示!我甚至不知道它的存在...谢谢! - Kobi
我的场景与Cem的回答不同,但不需要使用核心,而是使用C#。登录网址:"www.url.com/login",下载网址为:"www.url.com/data/3",但如何从您的回答中实现。@Kobi - Mazhar Khan

4
如果您想使用Html Agility Pack完成此操作,请使用以下代码。
CookieCollection Cookies = new CookieCollection();
            var web = new HtmlWeb();
            web.OverrideEncoding = Encoding.Default;
            web.UseCookies = true;
            web.PreRequest += (request) =>
            {
                if (request.Method == "POST")
                {
                    string payload = request.Address.Query;
                    byte[] buff = Encoding.UTF8.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);
                }

                request.CookieContainer.Add(Cookies);

                return true;
            };

            web.PostResponse += (request, response) =>
            {
                if (request.CookieContainer.Count > 0 || response.Cookies.Count > 0)
                {
                    Cookies.Add(response.Cookies);
                }
            };

            string baseUrl = "Your Website URL";
            string urlToHit = baseUrl + "?QueryString with Login Credentials";
            HtmlDocument doc = web.Load(urlToHit, "POST");

1
我不认为这是一个答案。你假设了存在 UserName/Password 参数,但对于大多数安全意识较强的 Web 开发人员来说,他们并没有这个参数。 - maplemale
我同意@maplemale的观点!在“查询字符串”上使用用户凭据是一个糟糕的想法(即使加密)。这不是一个通用的解决方案! - Igor

2
我花了几个小时研究这个主题,实际上找到了一个非常简单的解决方案。
我有:
.net core 1.1.2
HttmlAgilityPack 1.4.9.5
登录网址:www.url.com/login。
用于urlData的网址:"www.url.com/data/3" => 要获取此网址,您应该已经连接。
以下是我所做的,它只是起作用了:
HttpClient hc = new HttpClient();

HttpResponseMessage resultLogin = await hc.PostAsync(urlLogin, new StringContent("login=myUserName&password=myPaswordValue", Encoding.UTF8, "application/x-www-form-urlencoded"));

HttpResponseMessage resultPlaylist = await hc.GetAsync(urlData);

Stream stream = await resultPlaylist.Content.ReadAsStreamAsync();

HtmlDocument doc = new HtmlDocument();

doc.Load(stream);

string webContent = doc.DocumentNode.InnerHtml;  => it works

我认为您需要首先登录您的HttpClient,然后才能发送您想要的请求。祝使用愉快!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接