zoukankan      html  css  js  c++  java
  • c# 爬虫(二) 模拟登录

    有了上一篇的介绍,这次我们来说说模拟登录,上一篇见 :c# 爬虫(一) HELLO WORLD

    原理

    我们知道,一般需要登录的网站,服务器和客户端都会有一段时间的会话保持,而这个会话保持是在登录时候建立的, 服务端和客户端都会持有这个KEY,在后续访问时,都需要核对这两个KEY是否一致。 而客户端的这个KEY就存在cookie中。 因此,我们需要获取登录后的cookie值,并在后续的访问中,都添加这个cookie。这样才能做到模拟登录的效果。

    例子:

    我们以获取博客园首页的园龄为例。需要做三步

    1. 模拟登录博客园

    2. 构建个人主页的Request请求,包括cookie

    3. 获取个人主页的数据后, 分析页面,并获取园龄的数据。

    代码如下:

    复制代码
    static void Main(string[] args)
            {
                //string html= Hello();
                string html = LoginSimulation();
                Console.WriteLine(html);
                Console.Read();
            }
     static string LoginSimulation()
            {
                
                string url = "https://passport.cnblogs.com/user/signin";
                string postData = "{"input1":"MvxmwEWfUF26IvKNa1dUiZn1xmSBhNW0wJyoaUlDPXoh+Mb+z2eZK3r3c9Jd0aT0/Wzz3ht7LMeTllu8ISY9nfQIuKB0C19Y9/IfKYSktpZZOVaKx/XP3i/mGxXC3K5m2la91ViRh3BO36xT4E98dbqVHPtynjuNafuVIBF5a2M=","input2":"xxxx":false}";
    
                //1.获取登录Cookie
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
                req.Method = "POST";// POST OR GET, 如果是GET, 则没有第二步传参,直接第三步,获取服务端返回的数据
                req.AllowAutoRedirect = false;//服务端重定向。一般设置false
                req.ContentType = "application/x-www-form-urlencoded";//数据一般设置这个值,除非是文件上传
    
                byte[] postBytes = Encoding.UTF8.GetBytes(postData);
                req.ContentLength = postBytes.Length;
                Stream postDataStream = req.GetRequestStream();
                postDataStream.Write(postBytes, 0, postBytes.Length);
                postDataStream.Close();
    
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                string cookies = resp.Headers.Get("Set-Cookie");//获取登录后的cookie值。
    
                //2.登录想爬取页面的构造,主要多一个Cookie的构造
                string contentUrl = "https://home.cnblogs.com/u/xinjian/";
                HttpWebRequest reqContent = (HttpWebRequest)WebRequest.Create(contentUrl);
                reqContent.Method = "GET";
                reqContent.AllowAutoRedirect = false;//服务端重定向。一般设置false
                reqContent.ContentType = "application/x-www-form-urlencoded";//数据一般设置这个值,除非是文件上传
    
                reqContent.CookieContainer = new CookieContainer();
                reqContent.CookieContainer.SetCookies(reqContent.RequestUri, cookies);//将登录的cookie值赋予此次的请求。
    
                HttpWebResponse respContent = (HttpWebResponse)reqContent.GetResponse();
                string html = new StreamReader(respContent.GetResponseStream()).ReadToEnd();
    
                //3. 分析读取该页面的数据,可以使用HtmlAgilityPack第三方类,这里比较简单,自己写个获取方法就行
                string age= GetVal(html, "<span title='入园时间:2010-6-28'>", "</span>");
                return age;
            }
    复制代码

    注意事项

     1. 本次模拟登录,我发现chrome的开发人员工具,并没有抓到真正的Post包,和我之前遇到的情况一样, 后来还是使用了httpwatch后,才抓到了真正的数据包。博客园做的不错,提交的数据进行了加密。 当然我的密码我也已经改成了XXX,用户需要运行的话,需要自行抓包获取对应的postData。

    2. 针对cookie的赋值,主要由这两句完成

                reqContent.CookieContainer = new CookieContainer();
                reqContent.CookieContainer.SetCookies(reqContent.RequestUri, cookies);//将登录的cookie值赋予此次的请求。

    但是听说C#封装的不是很好,有时候会漏掉数据,但我目前还没遇到过, 如果遇到,需要将cookie的string手工转换成CookieCollection,并赋予CookieContainer。

    3. 针对ASP.NET的网页, 会存在__VIEWSTATE & __EVENTVALIDATION 这两个post字段, 对于没建立会话时,这两个值是不会变的,而一旦建立会话(模拟登陆后),每次访问的页面,这两个值都会改变, 解决办法是先使用GET获取该页面的数据后,获取这两个字段的值, 然后在post的时候,进行赋值。 

    4. 在遇到500错误的时候,说实话,我也很头疼,不知道如何调试,但我总结下来,一定是request构建的不对。主要查看如下问题:

      4.1. 对比post的数据的key和value,看看格式是否正确,如是否进行了编码 WebUtility.UrlEncode()。 

      4.2. 对比post的数据的,是否Post了全部的数据, 当然这里不光是当前页面,有时候还会用到其他页面,我举个例子, 我在订单页面上传附件, 在附件上传页面,发现并没有Post订单的id,那么这个时候,就需要查找订单的id服务端是什么时候获取的,这个时候就需要猜了,有可能是在打开订单页面的时候,服务端就把此id存储到session中了。所以先需要模拟打开订单页面,然后在模拟订单附件上传的post。

      4.3 注意是是否犯了__VIEWSTATE & __EVENTVALIDATION的错误,注意,针对数据型的post,需要进行urlEncode。

      4.4 Request的Head是否构建全了, 有时候客户端会提交自定义的head,注意查看。同时UserAgent有时候也会需要进行变化,但目前我还没遇到过。

      4.5. 如果确定Post的数据全了,并且还是500错误的话,考虑下是否cookie有问题,虽然我还没遇到过。

    目前就想到这么多,模拟登录当时我也卡了两天,主要当时对__VIEWSTATE & __EVENTVALIDATION的理解还是不够,后续如果有疑问的话,我会专门开一篇ASP.NET的模拟登录。

    参考文献:

    http://www.crifan.com/emulate_login_website_using_csharp/

    http://www.cnblogs.com/zuoguanglin/archive/2012/03/28/2421153.html

    https://msdn.microsoft.com/en-us/library/ms972976.aspx

  • 相关阅读:
    CodeForces 19D Points (线段树+set)
    FZU 2105 Digits Count
    HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
    HDU 5634 Rikka with Phi (线段树)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高 转圈游戏(暴力快速幂)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
    Java实现 蓝桥杯 算法提高VIP Substrings(暴力)
  • 原文地址:https://www.cnblogs.com/cuihongyu3503319/p/14773125.html
Copyright © 2011-2022 走看看