C#WebClient登录accounts.google.com

我很难尝试使用webclient对accounts.google.com进行身份validation

我正在使用C#WebClient对象来实现以下function。

我将表单字段提交到https://accounts.google.com/ServiceLoginAuth?service=oz

这是POST字段:

service=oz dsh=-8355435623354577691 GALX=33xq1Ma_CKI timeStmp= secTok= Email=test@test.xom Passwd=password signIn=Sign in PersistentCookie=yes rmShown=1 

现在,在我提交数据之前加载登录页面时,它有以下标题:

 Content-Type text/html; charset=UTF-8 Strict-Transport-Security max-age=2592000; includeSubDomains Set-Cookie GAPS=1:QClFh_dKle5DhcdGwmU3m6FiPqPoqw:SqdLB2u4P2oGjt_x;Path=/;Expires=Sat, 21-Dec-2013 07:31:40 GMT;Secure;HttpOnly Cache-Control no-cache, no-store Pragma no-cache Expires Mon, 01-Jan-1990 00:00:00 GMT X-Frame-Options Deny X-Auto-Login realm=com.google&args=service%3Doz%26continue%3Dhttps%253A%252F%252Faccounts.google.com%252FManageAccount Content-Encoding gzip Transfer-Encoding chunked Date Thu, 22 Dec 2011 07:31:40 GMT X-Content-Type-Options nosniff X-XSS-Protection 1; mode=block Server GSE 

好了,现在我如何使用WebClient Class来包含这些标题?

我试过webClient_.Headers.Add(); 但效果有限,总是返回登录页面。

以下是我使用的课程。 非常感谢任何帮助。


获取登录页面

  public void LoginPageRequest(Account acc) { var rparams = new RequestParams(); rparams.URL = @"https://accounts.google.com/ServiceLoginAuth?service=oz"; rparams.RequestName = "LoginPage"; rparams.Account = acc; webClient_.DownloadDataAsync(new Uri(rparams.URL), rparams); } void webClient__DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) { RequestParams rparams = (RequestParams)e.UserState; if (rparams.RequestName == "LoginPage") { ParseLoginRequest(e.Result, e.UserState); } } 

现在使用HtmlAgilityPack获取表单字段并将它们添加到Parameters集合中

  public void ParseLoginRequest(byte[] data, object UserState) { RequestParams rparams = (RequestParams)UserState; rparams.ClearParams(); ASCIIEncoding encoder = new ASCIIEncoding(); string html = encoder.GetString(data); HtmlNode.ElementsFlags.Remove("form"); HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(html); HtmlNode form = doc.GetElementbyId("gaia_loginform"); rparams.URL = form.GetAttributeValue("action", string.Empty); rparams.RequestName = "LoginPost"; var inputs = form.Descendants("input"); foreach (var element in inputs) { string name = element.GetAttributeValue("name", "undefined"); string value = element.GetAttributeValue("value", ""); if (!name.Equals("undefined")) { if (name.ToLower().Equals("email")) { value = rparams.Account.Email; } else if (name.ToLower().Equals("passwd")) { value = rparams.Account.Password; } rparams.AddParam(name,value); Console.WriteLine(name + "-" + value); } } webClient_.UploadValuesAsync(new Uri(rparams.URL),"POST", rparams.GetParams,rparams); 

发布数据后,我得到登录页面而不是重定向或成功消息。

我究竟做错了什么?

在一些摆弄之后,看起来WebClient类不是解决这个特定问题的最佳方法。

为了实现以下目标,我必须跳到WebRequest下面的一个级别。

在制作WebRequest(HttpWebRequest)并使用HttpWebResponse时,可以设置CookieContainer

  webRequest_ = (HttpWebRequest)HttpWebRequest.Create(rparams.URL); webRequest_.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; CookieContainer cookieJar = new CookieContainer(); webRequest_.CookieContainer = cookieJar; string html = string.Empty; try { using (WebResponse response = webRequest_.GetResponse()) { using (var streamReader = new StreamReader(response.GetResponseStream())) { html = streamReader.ReadToEnd(); ParseLoginRequest(html, response,cookieJar); } } } catch (WebException e) { using (WebResponse response = e.Response) { HttpWebResponse httpResponse = (HttpWebResponse)response; Console.WriteLine("Error code: {0}", httpResponse.StatusCode); using (var streamReader = new StreamReader(response.GetResponseStream())) Console.WriteLine(html = streamReader.ReadToEnd()); } } 

然后在制作post时以下列方式使用相同的Cookie容器

  webRequest_ = (HttpWebRequest)HttpWebRequest.Create(rparams.URL); webRequest_.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; webRequest_.Method = "POST"; webRequest_.ContentType = "application/x-www-form-urlencoded"; webRequest_.CookieContainer = cookieJar; var parameters = new StringBuilder(); foreach (var key in rparams.Params) { parameters.AppendFormat("{0}={1}&",HttpUtility.UrlEncode(key.ToString()), HttpUtility.UrlEncode(rparams.Params[key.ToString()])); } parameters.Length -= 1; using (var writer = new StreamWriter(webRequest_.GetRequestStream())) { writer.Write(parameters.ToString()); } string html = string.Empty; using (response = webRequest_.GetResponse()) { using (var streamReader = new StreamReader(response.GetResponseStream())) { html = streamReader.ReadToEnd(); } } 

所以这很有效,这段代码不适合生产使用,可以/应该进行优化。 以此为例。

这是一个在答案窗格中编写并且未经测试的快速示例。 您可能需要从一些表单值的初始请求中解析一些值以进入formData。 我的很多代码都基于这种类型的进程,除非我们需要刮掉facebook speako类型的站点,在这种情况下ajax使我们使用不同的方法。

 using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; namespace GMailTest { class Program { private static NameValueCollection formData = new NameValueCollection(); private static CookieAwareWebClient webClient = new CookieAwareWebClient(); static void Main(string[] args) { formData.Clear(); formData["service"] = "oz"; formData["dsh"] = "-8355435623354577691"; formData["GALX"] = "33xq1Ma_CKI"; formData["timeStmp"] = ""; formData["secTok"] = ""; formData["Email"] = "test@test.xom"; formData["Passwd"] = "password"; formData["signIn"] = "Sign in"; formData["PersistentCookie"] = "yes"; formData["rmShown"] = "1"; byte[] responseBytes = webClient.UploadValues("https://accounts.google.com/ServiceLoginAuth?service=oz", "POST", formData); string responseHTML = Encoding.UTF8.GetString(responseBytes); } } public class CookieAwareWebClient : WebClient { public CookieAwareWebClient() : this(new CookieContainer()) { } public CookieAwareWebClient(CookieContainer c) { this.CookieContainer = c; this.Headers.Add("User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5"); } public CookieContainer CookieContainer { get; set; } protected override WebRequest GetWebRequest(Uri address) { WebRequest request = base.GetWebRequest(address); if (request is HttpWebRequest) { (request as HttpWebRequest).CookieContainer = this.CookieContainer; } return request; } } }