使用WebClient或WebRequest登录网站并访问数据

15

我正在尝试使用WebClient / WebRequest访问网站上的受限数据。该网站没有官方API,因此我想要做的就是填写HTML表单并将值发布到服务器,以便我登录。

我尝试了这个这个,但看起来即将到来的请求没有被记录为已登录。

后一个示例更为吸引人,因为我显然更喜欢WebClient,但旧版的WebRequest也可以。

无论如何,在第一个示例中,我认为它确实已登录,但访问私人数据的即将到来的请求会返回一条消息为“这是会员专属内容”的页面。

如何使WebClient保持登录状态?


可能是C#通过程序登录网站的重复问题。 - RyBolt
2个回答

27

更新:

请参考我下面的评论


以下是我所做的事情,并且它有效(来源)。

首先添加这个类:

namespace System.Net
{
  using System.Collections.Specialized;
  using System.Linq;
  using System.Text;

  public class CookieAwareWebClient : WebClient
  {
    public void Login(string loginPageAddress, NameValueCollection loginData)
    {
      CookieContainer container;

      var request = (HttpWebRequest)WebRequest.Create(loginPageAddress);

      request.Method = "POST";
      request.ContentType = "application/x-www-form-urlencoded";

      var query = string.Join("&", 
        loginData.Cast<string>().Select(key => $"{key}={loginData[key]}"));

      var buffer = Encoding.ASCII.GetBytes(query);
      request.ContentLength = buffer.Length;
      var requestStream = request.GetRequestStream();
      requestStream.Write(buffer, 0, buffer.Length);
      requestStream.Close();

      container = request.CookieContainer = new CookieContainer();

      var response = request.GetResponse();
      response.Close();
      CookieContainer = container;
    }

    public CookieAwareWebClient(CookieContainer container)
    {
      CookieContainer = container;
    }

    public CookieAwareWebClient()
      : this(new CookieContainer())
    { }

    public CookieContainer CookieContainer { get; private set; }

    protected override WebRequest GetWebRequest(Uri address)
    {
      var request = (HttpWebRequest)base.GetWebRequest(address);
      request.CookieContainer = CookieContainer;
      return request;
    }
  }
}

使用方法:

public static void Main()
{
  var loginAddress = "www.mywebsite.com/login";
  var loginData = new NameValueCollection
    {
      { "username", "shimmy" },
      { "password", "mypassword" }
    };

  var client = new CookieAwareWebClient();
  client.Login(loginAddress, loginData);
}

1
@Anthony,如果你在非静态上下文中遇到问题,请使用System.Text.Encoding而不是Encoding。 - Neshta
4
您不能使用 loginData.ToString() 进行登录,因为它只会返回类型名称。 - Kyle Gobel
1
它曾经可以工作。无论如何,你们可以使用FormUrlEncodedContent然后使用ReadAsStringAsync。不管怎样,这个答案在发布时是好的,我建议使用HttpClient,提供一个覆盖SendAsync以登录的DelegatingHandler。我希望有时间更新这个答案。 - Shimmy Weitzhandler
4
无论如何,我已编辑了我的回答,希望现在能够工作。不要忘记,与其投反对票并生气,这是一个开放的网站,你可以编辑我的回答,以此回报社区和未来查看此答案的其他人。 - Shimmy Weitzhandler
2
@Shimmy,这对我无效,因为服务器总是返回200 OK代码,但是使用此答案,我可以检查容器中是否包含名为.ASPXAUTH的cookie以正确的站点,这样做就可以了。 - Dennis van Gils
显示剩余5条评论

5

HTTP是无状态的。因此,您无法使WebClient永久登录。在HTTP中不存在会话的概念。服务器端技术(如ASP.NET)通过使用cookie或查询字符串参数来模拟具有状态的行为,从而实现会话的概念,并在每个请求中来回发送。话虽如此,您可以从WebClient模拟浏览器的操作。如果您可以访问该网站,请使用正确的凭据连接到它并使用Fiddler捕获流量。然后,确保WebClient发送正确的cookie、请求头、查询字符串等,与浏览器完全相同。


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