以编程方式使用C#登录网站

时间:2014-09-10 02:12:13

标签: c# login httpwebrequest httpwebresponse

所以,我一直在网上搜索,试图了解如何使用C#以编程方式登录网站。我不想使用网络客户端。我想我想使用像HttpWebRequest和HttpWebResponse这样的东西,但我不知道这些类是如何工作的。

我想我正在寻找有人解释他们的工作方式以及成功登录WordPress,电子邮件帐户或任何要求您填写带有用户名的表单的网站所需的步骤和密码。

这是我的一次尝试:

// Declare variables
        string url = textBoxGetSource.Text;
        string username = textBoxUsername.Text;
        string password = PasswordBoxPassword.Password;

        // Values for site login fields - username and password html ID's
        string loginUsernameID = textBoxUsernameID.Text;
        string loginPasswordID = textBoxPasswordID.Text;
        string loginSubmitID = textBoxSubmitID.Text;

        // Connection parameters
        string method = "POST";
        string contentType = @"application/x-www-form-urlencoded";
        string loginString = loginUsernameID + "=" + username + "&" + loginPasswordID + "=" + password + "&" + loginSubmitID;
        CookieContainer cookieJar = new CookieContainer();
        HttpWebRequest request;

        request = (HttpWebRequest)WebRequest.Create(url);
        request.CookieContainer = cookieJar;
        request.Method = method;
        request.ContentType = contentType;
        request.KeepAlive = true;
        using (Stream requestStream = request.GetRequestStream())
        using (StreamWriter writer = new StreamWriter(requestStream))
        {
            writer.Write(loginString, username, password);
        }

        using (var responseStream = request.GetResponse().GetResponseStream())
        using (var reader = new StreamReader(responseStream))
        {
            var result = reader.ReadToEnd();
            Console.WriteLine(result);
            richTextBoxSource.AppendText(result);
        }

        MessageBox.Show("Successfully logged in.");

我不知道我是否在正确的轨道上。我最终被退回到我尝试的任何网站的登录屏幕。我已经下载了Fiddler,并且能够收集一些关于哪些信息发送到服务器的信息,但我觉得完全迷失了。如果有人能在这里说清楚,我会非常感激。

2 个答案:

答案 0 :(得分:22)

以编程方式登录网站很困难,并且与网站实现其登录过程的方式紧密相关。您的代码无效的原因是您在请求/回复中没有处理任何此类代码。

我们以fif.com为例。当您输入用户名和密码时,会发送以下发布请求:

POST https://fif.com/login?task=user.login HTTP/1.1
Host: fif.com
Connection: keep-alive
Content-Length: 114
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: https://fif.com
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.103 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: https://fif.com/login?return=...==
Accept-Encoding: gzip,deflate
Accept-Language: en-US,en;q=0.8
Cookie: 34f8f7f621b2b411508c0fd39b2adbb2=gnsbq7hcm3c02aa4sb11h5c87f171mh3; __utma=175527093.69718440.1410315941.1410315941.1410315941.1; __utmb=175527093.12.10.1410315941; __utmc=175527093; __utmz=175527093.1410315941.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmv=175527093.|1=RegisteredUsers=Yes=1

username=...&password=...&return=aHR0cHM6Ly9maWYuY29tLw%3D%3D&9a9bd5b68a7a9e5c3b06ccd9b946ebf9=1

注意cookie(特别是第一个,你的会话令牌)。注意发送的神秘网址编码返回值。如果服务器注意到这些缺失,则不会让您登录。<​​/ p>

HTTP/1.1 400 Bad Request

或者更糟糕的是,登录页面的200响应,其中包含错误消息。

但是,让我们假装您能够收集所有这些神奇的值并将它们传递给HttpWebRequest对象。该网站不知道差异。它可能会回应这样的事情。

HTTP/1.1 303 See other
Server: nginx
Date: Wed, 10 Sep 2014 02:29:09 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Location: https://fif.com/

希望你对此有所期待。但是如果你已经做到这一点,你现在可以使用现在验证的会话令牌以编程方式启动对服务器的请求,并获得预期的HTML。

GET https://fif.com/ HTTP/1.1
Host: fif.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.103 Safari/537.36
Referer: https://fif.com/login?return=aHR0cHM6Ly9maWYuY29tLw==
Accept-Encoding: gzip,deflate
Accept-Language: en-US,en;q=0.8
Cookie: 34f8f7f621b2b411508c0fd39b2adbb2=gnsbq7hcm3c02aa4sb11h5c87f171mh3; __utma=175527093.69718440.1410315941.1410315941.1410315941.1; __utmb=175527093.12.10.1410315941; __utmc=175527093; __utmz=175527093.1410315941.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmv=175527093.|1=RegisteredUsers=Yes=1

这一切都是针对fif.com的 - 对于另一个网站来说,这个杂耍的cookie,令牌和重定向将完全不同。根据我的经验(特别是该网站),您可以通过三种方式浏览登录墙。

  1. 写一个非常复杂和脆弱的剧本来围绕网站的程序跳舞
  2. 使用浏览器手动登录网站,获取魔术值,然后将其插入请求对象或
  3. 创建一个脚本以自动selenium为您执行此操作。
  4. Selenium可以处理所有的杂耍,最后你可以拉出饼干并正常发出请求。以下是fif的一个例子:

    //Run selenium
    ChromeDriver cd = new ChromeDriver(@"chromedriver_win32");
    cd.Url = @"https://fif.com/login";
    cd.Navigate();
    IWebElement e = cd.FindElementById("username");
    e.SendKeys("...");
    e = cd.FindElementById("password");
    e.SendKeys("...");
    e = cd.FindElementByXPath(@"//*[@id=""main""]/div/div/div[2]/table/tbody/tr/td[1]/div/form/fieldset/table/tbody/tr[6]/td/button");
    e.Click();
    
    //Get the cookies
    foreach(OpenQA.Selenium.Cookie c in cd.Manage().Cookies.AllCookies)
    {
        string name = c.Name;
        string value = c.Value;
        cc.Add(new System.Net.Cookie(name,value,c.Path,c.Domain));
    }
    
    //Fire off the request
    HttpWebRequest hwr = (HttpWebRequest) HttpWebRequest.Create("https://fif.com/components/com_fif/tools/capacity/values/");
    hwr.CookieContainer = cc;
    hwr.Method = "POST";
    hwr.ContentType = "application/x-www-form-urlencoded";
    StreamWriter swr = new StreamWriter(hwr.GetRequestStream());
    swr.Write("feeds=35");
    swr.Close();
    
    WebResponse wr = hwr.GetResponse();
    string s = new System.IO.StreamReader(wr.GetResponseStream()).ReadToEnd();
    

答案 1 :(得分:1)

结帐this发布。这是另一种做法,你不需要安装任何软件包,尽管使用Selenium可能更容易。

  

&#34;您可以继续使用WebClient进行POST(而不是GET,即   您目前正在使用的HTTP verb与DownloadString一起使用,但是我   认为你会发现使用(稍微)较低级别更容易   类WebRequest和WebResponse。

     

这有两个部分 - 第一部分是发布登录表单,   第二是恢复&#34; Set-cookie&#34;标题并将其发回   服务器为&#34; Cookie&#34;以及您的GET请求。服务器会   从现在开始使用此cookie来识别您(假设它正在使用   基于cookie的身份验证,我非常有信心   页面返回一个Set-cookie标题,其中包含&#34; PHPSESSID&#34;)。

           

发布到登录表单

     

表单帖子很容易模拟,它只是格式化你的情况   发布数据如下:

field1=value1&field2=value2
     

使用我从Scott Hanselman改编的WebRequest和代码,这里是   如何将表单数据发布到您的登录表单:

string formUrl = "http://www.mmoinn.com/index.do?PageModule=UsersAction&Action=UsersLogin";
     

注意:这是表单POST的URL,而不是表单的URL   (您可以在HTML的表单标记的&#34; action&#34;属性中找到它

string formParams = string.Format("email_address={0}&password={1}", "your email", "your password");
string cookieHeader;
WebRequest req = WebRequest.Create(formUrl);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(formParams);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
    os.Write(bytes, 0, bytes.Length);
}
WebResponse resp = req.GetResponse();
cookieHeader = resp.Headers["Set-cookie"];
     

以下是您应该在Set-cookie标头中看到的示例   您的登录表单:

PHPSESSID=c4812cffcf2c45e0357a5a93c137642e; path=/; domain=.mmoinn.com,wowmine_referer=directenter; path=/;
     

域= .mmoinn.com,朗= EN;   路径= /;域= .mmoinn.com,adt_usertype =其它,adt_host = -

           

获取登录表单后面的页面

     

现在,您可以对您需要的页面执行GET请求   登录。

string pageSource;
string getUrl = "the url of the page behind the login";
WebRequest getRequest = WebRequest.Create(getUrl);
getRequest.Headers.Add("Cookie", cookieHeader);
WebResponse getResponse = getRequest.GetResponse();
using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
{
    pageSource = sr.ReadToEnd();
}
     

修改

     

如果您需要查看第一个POST的结果,可以恢复   它返回的HTML:

using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
{
    pageSource = sr.ReadToEnd();
}
     

将其直接放在cookieHeader = resp.Headers["Set-cookie"];下方   然后检查pageSource中保存的字符串。&#34;