C#生成一个动态cookie,该站点将接受?

时间:2014-07-05 17:12:48

标签: c# .net image winforms cookies

我已尝试过在网上找到的所有相关解决方案,但他们都因某些原因拒绝工作。这也不起作用:C# - HttpWebRequest POST (Login to Facebook),因为我们使用不同的方法。

我没有使用POST方法,而是使用GET方法,它正在请求中使用。我正在使用的网站不需要任何登录凭据来获取图像。 (该站点的大多数其他根域不需要cookie。)

下面的代码是我想让程序像基于网络的版本一样获得图像的一部分,但是有一些问题。

之前,我试图使用普通的WebClient来下载图像,因为它拒绝以PictureBox控件接受的任何方式显示。但后来我切换到了HttpWebRequest。

我尝试从中获取图片的网站的特定根域需要cookie。

下面是一个代码片段,它基本上试图从网站获取图像。唯一的麻烦是,除非您在HttpWebRequest中传递一些内容以及cookie,否则几乎不可能从网站获取图像。

目前,我正在使用静态cookie作为临时解决方法。

HttpWebRequest _request = (HttpWebRequest)HttpWebRequest.Create(_URL);
_request.Method = WebRequestMethods.Http.Get;
_request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
_request.Headers.Set(HttpRequestHeader.AcceptEncoding, "gzip,deflate,sdch");
_request.Headers.Set(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.8");
_request.Headers.Set(HttpRequestHeader.CacheControl, "max-age=0");

_request.Host = "www.habbo" + _Country;
_request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36";

using (WebResponse _response = _request.GetResponse())
using (Stream _stream = _response.GetResponseStream())
{
    Image _image = Image.FromStream(_stream);
    _bitmap = new Bitmap(_image);
    string contentType = _response.ContentType;

    _PictureBox.Image = _bitmap;
}

让我们让以下变量:

_URL = "http://www.habbo.com/habbo-imaging/avatarimage?hb=img&user=aa&direction=2&head_direction=2&size=m&img_format=gif";

_Country = ".com";

我传递给HttpWebRequest的大部分内容都是通过查看Google Chrome开发人员工具的“网络”标签获得的。

基于网络的Habbo Imager版本似乎只是将人们引导到他们可以找到图像的页面,而他们的浏览器似乎以某种方式添加了cookie。我正在做的是不同的,因为他们只是显示图像所在的网站,但我想找到图像的真实位置,然后从中读取图像类型。

根据我从这个帖子中读到的内容,显然该网站似乎需要用户“访问”它们:点击here

我想知道的是,有没有更好的方法来获得服务器每次都乐意接受的有效cookie?

或者我是否需要以某种方式诱骗网站认为用户访问过该页面并看到它,从而使他们可能返回我们可能需要的cookie,即使用户没有看到该页面?

不太确定这是否意味着我需要以某种方式动态生成cookie。

我也不明白如何使用C#真正创建或获取cookie(并设置存储的cookie),所以如果可能的话,请使用一些例子。

我不想使用任何第三方库,或者更改我使用过多的代码。程序也不会发送两个GET请求,只是为了能够获得一个GET请求可以获得的内容。因此,这不起作用:Passing cookie with HttpWebRequest in winforms?

我使用的是.NET 4.0。

1 个答案:

答案 0 :(得分:1)

比初看起来有点复杂。浏览器实际上进行了两次调用。第一个返回一个带有一小段javascript的html脚本,执行时会设置一个cookie并重新加载页面。在你的c#代码中,你必须模仿它。

在您的表单类中添加一个实例变量,以保存多个httpwebrequest调用中的所有Cookie:

readonly CookieContainer cookiecontainer = new CookieContainer();

我创建了一个Builder方法,用于创建HttpWebRequest并返回一个HttpWebResponse。它需要一个namevaluecollection来将任何cookie添加到Cookiecontainer。

private HttpWebResponse Builder(string url, string host, NameValueCollection cookies)
{
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
    request.Method = WebRequestMethods.Http.Get;
    request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
    // _request.Headers.Set(HttpRequestHeader.AcceptEncoding, "gzip,deflate,sdch");
    request.Headers.Set(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.8");
    request.Headers.Set(HttpRequestHeader.CacheControl, "max-age=0");

    request.Host = host;
    request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36";

    request.CookieContainer = cookiecontainer;

    if (cookies != null)
    {
        foreach (var cookiekey in cookies.AllKeys)
        {
            request.CookieContainer.Add(
                new Cookie(
                    cookiekey, 
                    cookies[cookiekey],
                    @"/",
                    host));    
        }
    }
    return (HttpWebResponse) request.GetResponse();
}

如果传入的流是text / html内容类型,我们需要解析其内容并返回cookie名称和值。 Parse方法就是这样做的:

// find in the html and return the three parameters in a string array
// setCookie('YPF8827340282Jdskjhfiw_928937459182JAX666', '127.0.0.1', 10);
private static string[] Parse(Stream _stream, string encoding)
{
    const string setCookieCall = "setCookie('";

    // copy html as string
    var ms = new MemoryStream();
    _stream.CopyTo(ms);
    var html = Encoding.GetEncoding(encoding).GetString(ms.ToArray());

    // find setCookie call
    var findFirst = html.IndexOf(
        setCookieCall, 
        StringComparison.InvariantCultureIgnoreCase) + setCookieCall.Length;
    var last = html.IndexOf(");", findFirst, StringComparison.InvariantCulture);

    var setCookieStatmentCall = html.Substring(findFirst, last - findFirst);
    // take the parameters
    var parameters = setCookieStatmentCall.Split(new[] {','});
    for (int x = 0; x < parameters.Length; x++)
    {
        // cleanup
        parameters[x] = parameters[x].Replace("'", "").Trim();
    }
    return parameters;
}

现在我们的构建块已经完成,我们可以从Click方法开始调用我们的方法。我们使用循环来调用Builder两次以从给定的url获取结果。根据收到的内容类型,我们要么从流中解析或创建图像。

private void button1_Click(object sender, EventArgs e)
{
    var cookies = new NameValueCollection();
    for (int tries = 0; tries < 2; tries++)
    {
        using (var response = Builder(_URL, "www.habbo" + _Country, cookies))
        {
            using (var stream = response.GetResponseStream())
            {
                string contentType = response.ContentType.ToLowerInvariant();
                if (contentType.StartsWith("text/html"))
                {
                    var parameters = Parse(stream, response.CharacterSet);
                    cookies.Add(parameters[0], parameters[1]);
                }
                if (contentType.StartsWith("image"))
                {
                    pictureBox1.Image = Image.FromStream(stream);
                    break; // we're done, get out
                }
            }
        }
    }
}

谨慎的话

此代码适用于您问题中的网址。我没有采取任何措施来处理其他模式和/或例外。您可以自行添加。此外,在进行此类抓取时,请确保网站所有者允许此操作。