采集需要登录后的网页(重定向后cookie丢失问题)

在采集需要登陆后访问的页面中,采集程序需要保存登录后获取的cookie,由于有些网站登录验证成功后就将用户直接重定向到目标页,
如: Response.Redirect("/user/index.asp") 
响应头部含如下参数
Location: /user/index.aspx
Set-Cookie: .ASPXAUTH=3DABFC1691FD31F16EFF68D55202130196135D8B3F0A8B630C956242FBBA802EDB912E0B84D6601A6F425824DA1C28AFBDF04E6B4D0CA6E7D7EBB7DD2A212F5FFFF2921DF35CE098F603CE31E56D71AD68CC23117123E11AB8323AD86B648665; expires=Thu, 04-Dec-2008 02:59:15 GMT; path=/; HttpOnly

这样在使用WebClient时,不能捕捉到需要的cookie,这个时候就需要使用HttpWebRequest(WebRequest针对http协议的实现)

获取cookieContainer

---------------------------------------
        private System.Net.CookieContainer GetCookieContainer(string logUrl,byte[] data)
        {
            HttpWebRequest request = HttpWebRequest.Create(logUrl) as HttpWebRequest;
            request.AllowAutoRedirect = false;//禁止自动重定向
            request.Method = "Post"; //使用post方法
            request.ContentType = "application/x-www-form-urlencoded";//form提交时使用urlencode
            request.ContentLength = data.Length;
            request.CookieContainer = new CookieContainer();
            Stream uploadStream=request.GetRequestStream();
            uploadStream.Write(data, 0, data.Length);
            uploadStream.Close();
            HttpWebResponse resposne = request.GetResponse() as HttpWebResponse;
            resposne.Close();
            return request.CookieContainer;//反会获取的cookieContainer
        }

 //登录后获取cookie再进行数据采集,需要导如System.IO,System.Net,System.Web等命名空间

 -------------------------------------------------

            string formData=@"Username=xxxx&Password=dafa34@234";//登录页面表单字段
            //使用gb2312进行Url编码
            formData= HttpUtility.UrlEncode(formData,Encoding.GetEncoding("gb2312"));
            //编码为字节数据
            byte[] data = Encoding.GetEncoding("gb2312").GetBytes(formData);

            //是需要登陆后获取的页面(数据采集页)
            Uri dataUri = new Uri("http://wow52.cn/admin/article.aspx");
            HttpWebRequest request = WebRequest.Create(dataUri) as HttpWebRequest;
            
           //设置来路,有些站点会检测访问来路来判断是否为盗链等.
           //使用WebRequest时你无法直接使用 request.Hands.Add("Referer","http://www.wow52.cn/log.aspx")
           //来添加标头
            request.Referer="http://www.wow52.cn/log.aspx";
            //一些其他设置
            //request.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*";
            //request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)";
            request.Method = "GET";
            //登录页地址,需要特别注意的是这个uri的域名必须要与上面一致
            //使用www.wow52.cn获取的cookieContainer只有在域名为www.wow52.cn时才会被附加上
            //对一些使用了二级域名的站点,各数据页二级域名各不相同的,可以将Cookie逐个取出
            //再拼接起来,如: cookieName1=cookieValue1;cookieName2=cookieValue2;...
            //将拼写后的字符串添加到Request.Headers中如:request.Headers.Add("Cookie", "拼接串");
            Uri logUri = new Uri("http://www.wow52.cn/log.aspx"); //这里设置为http://www.wow52.cn/区别上面dataUri的wow52.cn

            //调用上文的GetCookieContainer函数
            CookieContainer container = GetCookieContainer(logUri.ToString(), data);
          

//判断是否是同个域名(主机名)
 if (Uri.Compare(dataUri, logUri, UriComponents.Host, UriFormat.Safed, StringComparison.OrdinalIgnoreCase) != 0)
            {
                //逐个取出cookie并更改domain后,添加到request.CookieContainer中

                CookieCollection cookies = container.GetCookies(logUri);
                request.CookieContainer = new CookieContainer();
                foreach (Cookie cookie in cookies)
                {
                    cookie.Domain = dataUri.Host; //使用目标数据页的主机部分
                    request.CookieContainer.Add(cookie);
                }
         
            }
            else //domain相同
            {
                request.CookieContainer = container;
            }
            //获取响应数据
            HttpWebResponse response = request.GetResponse() as HttpWebResponse; 
            StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("gb2312"));
            string html = sr.ReadToEnd();
            response.Close();
            txtMsg.Text = html; //txtMsg是文本框

 ---------------------------

 注意,
1.上面代码是直接从vs2005复制过来的,没加格式化,方便于直接复制回去,

2.一般的数据采集下使用WebClient比较方便,也可以一起使用WebClient跟WebRequest.

3.WebRequest.AllowAutoRedirect=false;属性 来防止自动重定向

4.WebRequest 想设置Referer 标头时使用 WebRequest.Referer="xxxx" ,直接WebRequest.Headers.Add是不行的
   不过使用webClient时可以这么做.

5.注意上面的编码post数据一般要先进行urlEncode,并且指明
 request.ContentType = "application/x-www-form-urlencoded";
 webClient时使用 webClient.Headers.Add("Content-Type","application/x-www-form-urlencode");
 另外在将数据转化成byte[] data(字节数组时)请确认网站使用的编码是utf-8还是gb2312或其他,同样获取返会的数据后(指本类型的),也要根据站点的编码进行转化(到字符串)

 
6.上面使用formdata是虚拟的,呵呵,防止你黑了我的站(^_^),你如果要测试,请自己另外找个站点,另外.net表单提交时会有一些状态信息,这些你可以通过一向代理工具来获取,并分析得出需要的post数据格式.

 另外对于带图片验证码的登录,一般我们在使用WebRequest下载图片时需要同时保存下载图片时的临时SessionID(也是cookie),在提交表单时要将这个SessionID数据(cookie)附加到标头上,这样就可以通过验证,至于图片识别,一般使用图片框显示后人工识别(通用情况下).

参考资料
 HttpWebRequest

原文地址:https://www.cnblogs.com/yeye518/p/2231647.html