使用HttpWebRequest提交ASP.NET表单并保持Session和Cookie

由于种种原因,我们有时需要从互联网上抓取一些资料,有些页面可以直接打开,而有些页面必登录之后才能打开。本文介绍的是使用 HttpWebRequest 和 HttpWebResponse 自动填写提交 ASP.NET 表单并保持 Session 和 Cookie 的一个完整的例子。本文所有源代码:AutoPostWithCookies.rar

这里涉及到3个页面:MyLogin.aspx,
LoginOK.htm,Default.aspx:
1)MyLogin.aspx 页面

MyLogin.aspx 页面是登录页面,如果用户名和密码正确会生成 Session 和 Cookie(LoginSession、LoginCookie,然后转向 LoginOK.htm 页面。

2)LoginOK.htm 页面


LoginOK.htm 页面是一个跳转页面,几秒钟后会自动跳转到 Default.aspx 页面。

3)Default.aspx 页面

Default.aspx 页面是主界面,打开主界面时会判断 LoginSession 和 LoginCookie 的值是否正确,并把 Session 和 Cookie 的值显示出来。

提交ASP.NET表单(即完成自动登录)的代码如下:

    try
    {
        CookieContainer cookieContainer = new CookieContainer();


        
///////////////////////////////////////////////////
        // 1. 打开 MyLogin.aspx 页面,获得 VeiwState & EventValidation
        ///////////////////////////////////////////////////                
        // 设置打开页面的参数
        string URI = "http://localhost:1165/WebTest/MyLogin.aspx";
        HttpWebRequest request 
= WebRequest.Create(URI) as HttpWebRequest;
        request.Method 
= "GET";
        request.KeepAlive 
= false;

        
// 接收返回的页面
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        System.IO.Stream responseStream 
= response.GetResponseStream();
        System.IO.StreamReader reader 
= new System.IO.StreamReader(responseStream,Encoding.UTF8);
        
string srcString = reader.ReadToEnd();

        
// 获取页面的 VeiwState                
        string viewStateFlag = "id=\"__VIEWSTATE\" value=\"";
        int i = srcString.IndexOf(viewStateFlag) + viewStateFlag.Length;
        
int j = srcString.IndexOf("\"", i);
        string viewState = srcString.Substring(i, j - i);

        
// 获取页面的 EventValidation                
        string eventValidationFlag = "id=\"__EVENTVALIDATION\" value=\"";
        i = srcString.IndexOf(eventValidationFlag) + eventValidationFlag.Length;
        j 
= srcString.IndexOf("\"", i);
        string eventValidation = srcString.Substring(i, j - i);

        
///////////////////////////////////////////////////
        // 2. 自动填充并提交 MyLogin.aspx 页面
        ///////////////////////////////////////////////////
        // 提交按钮的文本
        string submitButton = "登录";

        
// 用户名和密码
        string userName = "1";
        
string password = "1";

        
// 将文本转换成 URL 编码字符串
        viewState = System.Web.HttpUtility.UrlEncode(viewState);
        eventValidation 
= System.Web.HttpUtility.UrlEncode(eventValidation);
        submitButton 
= System.Web.HttpUtility.UrlEncode(submitButton);

        
// 要提交的字符串数据。格式形如:user=uesr1&password=123
        string formatString = 
                 "userName={0}&password={1}&loginButton={2}&__VIEWSTATE={3}&__EVENTVALIDATION={4}";
        
string postString = 
                 string.Format(formatString, userName, password, submitButton, viewState, eventValidation);

        
// 将提交的字符串数据转换成字节数组
        byte[] postData = Encoding.ASCII.GetBytes(postString);

        
// 设置提交的相关参数
        request = WebRequest.Create(URI) as HttpWebRequest;
        request.Method 
= "POST";
        request.KeepAlive 
= false;
        request.ContentType 
= "application/x-www-form-urlencoded";
        request.CookieContainer = cookieContainer;
        request.ContentLength = postData.Length;

        
// 提交请求数据
        System.IO.Stream outputStream = request.GetRequestStream();
        outputStream.Write(postData, 
0, postData.Length);
        outputStream.Close();

        
// 接收返回的页面
        response = request.GetResponse() as HttpWebResponse;
        responseStream 
= response.GetResponseStream();
        reader 
= new System.IO.StreamReader(responseStream,Encoding.GetEncoding("GB2312"));
        srcString 
= reader.ReadToEnd();

        
///////////////////////////////////////////////////
        // 3. 打开 Default.aspx 页面
        ///////////////////////////////////////////////////
        // 设置打开页面的参数
        URI = "http://localhost:1165/WebTest/Default.aspx";
        request 
= WebRequest.Create(URI) as HttpWebRequest;
        request.Method 
= "GET";
        request.KeepAlive 
= false;
        request.CookieContainer = cookieContainer;

        
// 接收返回的页面
        response = request.GetResponse() as HttpWebResponse;
        responseStream 
= response.GetResponseStream();
        reader 
= new System.IO.StreamReader(responseStream, Encoding.UTF8);
        srcString 
= reader.ReadToEnd();

        
///////////////////////////////////////////////////
        // 4. 分析返回的页面
        ///////////////////////////////////////////////////
        //  
    }
    
catch (WebException we)
    {
        
string msg = we.Message;
    }  

说明:
1) 之所以能够保持 Session 和 Cookie 是因为使用了 Cookie 容器(CookieContainer),见红色的代码部分。
2) POST ASP.NET 页面时,需要把 VeiwState 和 EventValidation 数据也一同 POST 过去。

本文所有源代码:AutoPostWithCookies.rar

相关文章:使用WebClient自动填写并提交ASP.NET页面表单
             使用WebClient自动填写并提交ASP.NET页面表单的源代码
             在C#中使用正则表达式自动匹配并获取所需要的数据

本文地址:http://www.cnblogs.com/anjou/archive/2007/10/15/923770.html

posted on 2007-10-15 09:05 大豆男生 阅读(5723) 评论(59)  编辑 收藏 网摘 所属分类: .NET

评论

#1楼 2007-10-15 09:26 暗香浮动      

不错,我也准备要用这部分内容了还没有来得及考虑。
谢谢哦。
  回复  引用  查看    

#2楼 2007-10-15 09:31 大林[未注册用户]

代码写的真工整...   回复  引用    

#3楼 2007-10-15 10:45 Clark Zheng      

Good,前段时间刚搞完这个东西,由于懒没一直没写篇文章,呵呵   回复  引用  查看    

#4楼[楼主] 2007-10-15 10:51 大豆男生      

@暗香浮动
@大林
@Clark Zheng
我也是刚刚整理完,谢谢你们的关注!
  回复  引用  查看    

#5楼 2007-10-15 11:47 txdlf      

通过HttpWebResponse 获取页面的内容关键一点是要先分析出这个页面所需要的QueryString参数和Post参数。
这个阶段过后才能使用搂主所使用的技术来获取页面的内容,不过楼主目前的代码远没有达到通用的地步。因为前端时间所做的两个项目需要的数据主要来源于原有的web系统,所以对此深有体会
  回复  引用  查看    

#6楼 2007-10-15 11:56 txdlf      

还有对于这段代码:
foreach (Cookie cookie in response.Cookies)
cookieContainer.Add(cookie);
我记得好像不用手工处理,只要前后两次的页面请求代码:request.CookieContainer = cookieContainer
指向同一个变量(cookieContainer)就可以保留状态,所以关键是在两次请求之间保留cookieContainer变量,这个应该很容易的
  回复  引用  查看    

#7楼[楼主] 2007-10-15 11:56 大豆男生      

@txdlf
谢谢你的回复!
你说的很对,QueryString参数和Post参数很重要。我一般是通过一些工具来查看,比如: 网页数据分析工具HttpWatch,网络嗅探器等。
  回复  引用  查看    

#8楼[楼主] 2007-10-15 12:02 大豆男生      

@txdlf
哈哈,你很真的很认真细致,这方面也颇有经验啊!
在本例中
foreach (Cookie cookie in response.Cookies)
cookieContainer.Add(cookie);
确实是多余的。
  回复  引用  查看    

#9楼 2007-10-15 12:45 [阿毅][未注册用户]

foreach (Cookie cookie in response.Cookies)
cookieContainer.Add(cookie);

有问题哦!不能这样弄D。
  回复  引用    

#10楼 2007-10-15 12:45 [阿毅][未注册用户]

汗!原来有人说了。   回复  引用    

#11楼[楼主] 2007-10-15 12:59 大豆男生      

@txdlf
@[阿毅]
谢谢两位!代码已经做了修改:
把这个循环删除了!
foreach (Cookie cookie in response.Cookies)
cookieContainer.Add(cookie);

  回复  引用  查看    

#12楼 2007-10-15 13:07 韩现龙      

不错是不错,不过文章只对ASP.NET网站才有效。楼主应该再接再厉,写一些对任何网站的提交都有效的文章,比如说,对jsp类,对asp类的。其实都一样。用xmlHttpRequest就可以实现了。在WIndows编程中,用一个vb中的com组件inet实现post或get数据也可以。或者直接用.net中的WebBrowser亦可。   回复  引用  查看    

#13楼 2007-10-15 13:27 aspnetx      

差不多看到第四篇描述这个内容的文章了
印象最深的还是dudu老大的那篇
不过这篇也很值得回味.关键是理解了IE的工作方式就很容易理解这些代码了.
  回复  引用  查看    

#14楼 2007-10-15 13:41 Ak[未注册用户]

@aspnetx
我怎么没看搜到以前的文章?麻烦给个连接吧,谢了
  回复  引用    

#15楼[楼主] 2007-10-15 13:54 大豆男生      

@韩现龙
多谢你的关注,我以前也做个提交JSP页面的程序,其实提交JSP,ASP页面比ASP.NET还简单些。因为JSP和ASP没有VeiwState和EventValidation,获取页面的VeiwState和EventValidation步骤就不需要了。
  回复  引用  查看    

#16楼[楼主] 2007-10-15 13:57 大豆男生      

@aspnetx
把dudu老大的那篇链接过来看看吧,我也没有找到。
  回复  引用  查看    

#17楼 2007-10-15 14:44 aspnetx      

@Ak
@大豆男生

利用HttpRequest登录到某个网站,然后获取网站信息的程序示例http://www.cnblogs.com/dudu/articles/80713.html" target="_new">http://www.cnblogs.com/dudu/articles/80713.html

文章中经典的几句话(另:不知是否是老大的原作):

要点:
1。 通过附加一个cookiecontainer到httprequest对象中,可以得到登录后返回的代表SESSION ID的COOKIE。 见Login方法
2。 将此COOKIE包含在一个cookiecontainer中并附加到另一个HTTPREQUEST请求中,则可以实现SESSION的还原。见getPage方法
  回复  引用  查看    

#18楼[楼主] 2007-10-15 17:15 大豆男生      

@aspnetx
dudu 的“要点”说的不错,比较深入!
  回复  引用  查看    

#19楼 2007-10-20 19:55 47463102@qq.com[未注册用户]

我正要用啊但不知怎么用啊源代码放在哪啊??   回复  引用    

#20楼[楼主] 2007-10-21 08:42 大豆男生      

@47463102@qq.com
源代码这里下载:http://www.cnblogs.com/Files/anjou/AutoPostWithCookies.rar">AutoPostWithCookies.rar
  回复  引用  查看    

#21楼 2007-11-28 13:27 Sjq[未注册用户]

这个还是没办法解决啊...
楼主有没有使用网页调用的实例啊
  回复  引用    

#22楼[楼主] 2007-11-28 22:03 大豆男生      

@Sjq
网页调用的实例没有,方法是一样的,应该可以的。
  回复  引用  查看    

#23楼 2007-12-10 13:44 tguitars[未注册用户]

@大豆男生
如果在服务端把session清除了,那么这样就无效了?
例如在default,aspx的结束时,把 session清空。
  回复  引用    

#24楼[楼主] 2007-12-10 17:58 大豆男生      

@tguitars
服务器端为什要清空 Session?后续页面还要使用要 Session 和 Cookie 进行验证啊;如果后续页面不验证 Session 和 Cookie 那就没有必要“登录”了,直接打开后续页面就可以了。
  回复  引用  查看    

#25楼 2008-01-23 21:34 婲生魚      

有个问题,
如何判断我提交的网站需要什么cookies,我就传什么Cookies过去?
  回复  引用  查看    

#26楼 2008-01-23 21:35 婲生魚      

有个问题,
如何判断我提交的网站需要什么cookies,我就传什么Cookies

不好意思,我再发一遍,刚才没勾 有回复时邮件通知我, 嘿嘿

谢谢啦!
  回复  引用  查看    

#27楼[楼主] 2008-01-27 21:20 大豆男生      

@婲生魚
谢谢你的关注。判断提交的页面需要什么 cookies 可以用IE打开页面,然后通过一些工具来查看,比如: 网页数据分析工具 HttpWatch,网络嗅探器等。
  回复  引用  查看    

#28楼 2008-02-13 08:50 婲生魚[没登陆 ^_^][未注册用户]

@大豆男生
谢谢您的回复,我是说:程序里面,比如我先得到所有的Sessiion,Cookies,当我想提交到某给网页时,我不想自己写代码,指定传什么Session过去,
程序自动判断需要什么,就自动传什么过去.不知道我说清楚没啦,嘿嘿.
谢谢您的回复哦~!
  回复  引用    

#29楼[楼主] 2008-02-13 14:11 大豆男生      

@婲生魚[没登陆 ^_^]
cookieContainer中包括所有的Sessiion和Cookies,不需要判断什么的。
  回复  引用  查看    

#30楼 2008-02-15 10:33 婲生魚[没登陆 ^_^] [未注册用户]

首先我得用截包工具,知道这个页面需要什么Cookies,Session
再程序传这些东东过去,我们现在都是这样.
比如能不能,我指定传到这个页面,它自己判断出这个页面需要什么东东,再自动从cookieContainer中取这些Cookies传过去呢?
因为有些网站很歪,Cookies的顺序和他指定的不一样,就过不去.
不知道我说明白没啦.嘿.期待您的回复喔~.3Q
  回复  引用    

#31楼[楼主] 2008-02-16 10:24 大豆男生      

@婲生魚[没登陆 ^_^]
你的要求高了点呀,我查了一下好像很难做得到啊。
  回复  引用  查看    

#32楼 2008-02-18 17:27 婲生魚[没登陆 ^_^] [未注册用户]

嘿嘿,我想也是.那我就没问题问你了啦,有问题我们再互相交流喔.   回复  引用    

#33楼[楼主] 2008-02-19 09:40 大豆男生      

@婲生魚[没登陆 ^_^]
哈哈,欢迎!共同探讨吧!
  回复  引用  查看    

#34楼 2008-02-19 14:09 911      

好东西,兄弟谢谢你了!这个问题困扰我好几天了!   回复  引用  查看    

#35楼 2008-04-14 21:02 婲生魚[没登陆 ^_^] [未注册用户]

http://www.cnblogs.com/anjou/archive/2007/10/15/923770.html#1067574
推荐一看,我们可以学习一下
  回复  引用    

#36楼 2008-04-15 23:22 婲生魚[没登陆 ^_^] [未注册用户]

http://www.cnblogs.com/deerchao/archive/2007/08/09/849361.html
晕,现在一看,原来发错了地址...
  回复  引用    

#37楼[楼主] 2008-04-16 15:36 大豆男生      

@婲生魚
不错,学习了。
  回复  引用  查看    

#38楼 2008-06-26 13:07 可燃冰[未注册用户]

博主,你真好,那么认真的回复大家。我用vb.net2003,看不到你的源码,我想请教一下,只在三个地方对cookie进行处理就可以了吗?cookie不用获取就能调用吗?我通过抓包发现我的程序post的cookie仍然是空值,谢谢解答   回复  引用    

#39楼[楼主] 2008-06-26 20:46 大豆男生      

@可燃冰
谢谢你的关注。
1)只需在三个地方对cookie进行处理就可以了;
2)不用获取cookie。可以这么理解:CookieContainer 是 cookie 容器,cookie 是保存在这里,页面可以从 CookieContainer 这里读取 cookie。所以我们不用获取 Cookie。
  回复  引用  查看    

#40楼 2008-07-10 23:25 可燃冰[未注册用户]

谢谢,通过cookiecontainer还是没有得到,不过通过header.tostring得到了,虽然比较费事   回复  引用    

#41楼 2008-07-16 12:02 漂在水面的鱼[未注册用户]

我在做个相关功能的程序,不过提交到的是个jsp页面,我用 ie的一个插件获得的
一些头信息,可是从中没有找到 格式形如:user=uesr1&password=123
这之类的post数据,只是一些公共的数据,在获得的信息当中能看到Get的数据
285775860 晚上会上,希望能帮忙参考参考
  回复  引用    

#42楼[楼主] 2008-07-17 22:28 大豆男生      

@漂在水面的鱼
使用HttpWatch这个工具,可以比较清楚的看到页面 Post的数据。但数据的形式不是形如“user=uesr1&password=123 ”这样的。使用 HttpWatch 工具,在Post 数据标签页,你可以看到类似这样的数据:
参数 值
user user1
password 123
  回复  引用  查看    

#43楼 2008-07-19 00:07 漂在水面的鱼[未注册用户]

谢谢 楼主回复
我本来是用了个 ieHttpHeaders ,可并没有找到我想得到的数据
然后 用这个工具 可以测试到不少 登陆页面 在里面可以看到 诸如登陆信心之类的东西
  回复  引用    

#44楼 2008-07-19 00:08 漂在水面的鱼[未注册用户]

我去试试 httpwatch   回复  引用    

#45楼 2008-07-19 00:12 漂在水面的鱼[未注册用户]

对了 忘了问下 ,如果说网页用 到框架,会影响到程序捕获表单么?
谢谢
  回复  引用    

#46楼[楼主] 2008-07-19 08:25 大豆男生      

@漂在水面的鱼
带框架的我没有试过,不过我想对框架里的某个页面进行提交应该是一样的。
  回复  引用  查看    

#47楼 2008-07-20 23:16 漂在水面的鱼[未注册用户]

呵呵 谢谢楼主积极回复
我找了个 httpwatch
可是我记录网页的时候,工具提示不支持 我网页的地址格式...
让我买...是软件的原因,还是真的是不能识别网页地址呢?
第一次用这个,不大熟悉。麻烦给介绍下,或是给发个工具也可
谢谢。
  回复  引用    

#48楼 2008-07-21 12:22 漂在水面的鱼[未注册用户]

呵呵 我又来了
今天找了个可用的 httpwatch 工具,
能看到比较详细的信息了,
在 post选项卡里,看到了传递的表单数据,在stream里看到了传递的整个字符串,其中还包括一个sql语句。
可我在程序里将这个字符串放进去之后,程序还是没能得到执行后的页面,得到的html仍是表单页。。。困惑中。
  回复  引用    

#49楼 2008-07-21 12:29 漂在水面的鱼[未注册用户]

CookieContainer myCookieContainer = new CookieContainer();
string outdata = "";
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
myHttpWebRequest.ContentLength = indata.Length;
myHttpWebRequest.Method = "POST";
myHttpWebRequest.CookieContainer = myCookieContainer;
Stream myRequestStream = myHttpWebRequest.GetRequestStream();
StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
myStreamWriter.Write(indata);
myStreamWriter.Close();
myRequestStream.Close();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
myHttpWebResponse.Cookies = myCookieContainer.GetCookies(myHttpWebRequest.RequestUri);
Stream myResponseStream = myHttpWebResponse.GetResponseStream();
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("gb2312"));
outdata = myStreamReader.ReadToEnd();
myStreamReader.Close();
myResponseStream.Close();
return outdata;
我还试用过这段代码 indata就是那个字符串了
  回复  引用    

#50楼[楼主] 2008-07-21 21:16 大豆男生      

@漂在水面的鱼,没有看出上面的代码有什么问题。
http://www.cnblogs.com/Emoticons/baimantou/202015214.gif" alt="" />
  回复  引用  查看    

#51楼 2008-07-21 21:32 漂在水面的鱼[未注册用户]

呵呵 谢谢 楼主

我今天又看了下程序,发现了问题关键所在!!!!
post 的地址写错了.... 我当时差点掉桌子底下7
  回复  引用    

#52楼[楼主] 2008-07-22 08:34 大豆男生      

@漂在水面的鱼,问题解决了http://www.cnblogs.com/Emoticons/QQ/47.gif" alt="" />恭喜,恭喜!

  回复  引用  查看    

#53楼 2008-11-19 16:31 吉祥如意[未注册用户]

ie http analyzer 也是一个不错的查看header头的IR插件。建议大家用用。   回复  引用    

#54楼 2008-11-28 17:57 天使寻梦[未注册用户]

有一个问题不明白
用firefox查看cookie发现没有名为LoginCookie的cookie
也就是说并没有在客户端写入LoginCookie这个cookie
为什么会这样的呢
  回复  引用    

#55楼[楼主] 2008-11-30 15:35 大豆男生      

@天使寻梦
没在firefox上试过
  回复  引用  查看    

#56楼 2009-04-24 11:22 ivw[未注册用户]

你好,请问如果我想登录126邮箱这种页面怎样做呢。?用你上面的方法好像不行啊   回复  引用    

#57楼[楼主] 2009-04-25 09:18 大豆男生      

@ivw
你可以用网页数据分析工具HttpWatch等,看看其POST了哪些数据,然后再写程序。
  回复  引用  查看    

#58楼 2009-05-28 10:52 Jake.NET      

谢谢,写得很好。   回复  引用  查看    

#59楼 2009-06-01 16:38 SINOSoft      

我吧程序改成html post 数据 userid={0}&userpass={1}&submit1=submit ,为什么总是不能成功啊???   回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 923770




相关文章:

相关链接:

导航

公告


励志照亮人生,创业改变命运!

Blog 访问量,点击这里查看如何添加访问计数器。
<2007年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

统计

与我联系

搜索

 

常用链接

留言簿

我的标签

随笔分类(117)

随笔档案(121)

收藏夹(137)

我的连接

最新随笔

积分与排名

最新评论

阅读排行榜

评论排行榜