感情 程序 祭

本文介绍了一种利用程序自动解析在线个性测试题答案的方法,通过分析HTTP请求和使用正则表达式,实现对特定网站测试题的答案自动迭代获取。

感觉自己也快成了标题党,起了个这么吓人的名字,发一个以前写的小程序,同时也算是自己以前一段感情的一篇祭文,谁让俺是程序员呢,写祭文都要写得这么有社会主义特色。

她是我的一个师妹,几年前大家都在深圳,但由于各种原因也没有太多的接触,说句老实话本来对她就挺有好感的,可是后来她回南京了,结果大家天各一方。她也是一个很有才的mm,经常搞些古灵精怪的东西出来,比如有一次她让我测一下我对她的了解有多少,给了我一个网址:http://www.testren.com/mylist.aspx?userid=2656967(提醒一下各位gg,这是我自己的,她的没有经过她同意我也不可能放上来,对这篇文章里面技术感兴趣的TX也可以自己申请一个玩玩)。看看这个网站就知道了,它的创意主要就是给用户自己在上面出一些题目,然后发给自己的亲戚朋友姨妈姑爹,测一下对自己的了解程度有多少,后来还增加了点击广告提示答案(蛮有创意的)。开始我也觉得是小女孩喜欢玩的把戏,没多大放在心上,随便测了一下得了可怜的40分。

后来也不知道怎么地开始和她在网上有一搭没一搭的闲聊起来,我猜她有男朋友,当然她说没有(不过事实后来验证了我的直觉)。为了满足自己"罪恶"的偷窥欲,进一步了解她,我决定把她以前给我的测试题答案都迭代出来(嘿嘿,迭代,每个程序员都很熟悉的一个词)。

一、思路:

  1. 首先获取一下要偷窥的页面出了多少道题(总分是100分),假设所有题目的选项是A(总共ABCD四个选择),提交页面后算一下返回来的分数是多少,这个分数作为一个基准,保存在maxPoint变量里面,留给下面的迭代用。
  2. 然后开始迭代,先改变一下第一道题目的答案,把A改成B,提交,获取新的分数,如果分数大于maxPoint就说明改动的选项是正确答案,不然分数怎么会增加呢,对吧?好,分数增加就把分数和答案都保留下来,作为下一轮迭代的参考基准。第1题答案迭代完了就开始迭代第2题,依此类推。最后迭代的结果就是把最高分100和对应的答案选项迭代出来了。

二、准备知识:

但是也用到了一些关于Http请求和正则的一些知识,http协议可以在网上搜一下关于孙鑫老师的HTTP协议视频教程,正则的话就不说了,网上一大把,下面要用到的工具Fiddler2自身也有个视频教程。

三、页面分析:

借助web开发居家旅行必备工具:IEDevelopToolbar、Fiddler2。

  1. 题目总数:可以通过正则表达式 (\d+)、获取,匹配有多少个就有多少道题目(我的主页有20道题)

  2. 获取要提交的数据,首先我们可以手工提交两道题目,用Fiddler2分析一下提交的数据,

    作为有代表性的两道题目,我选择了第一道和最后一道,还要把答题者、email和所在地填上:

    分析Fiddler2截获的提交数据

    由于信息比较多,我把与提交请求页相关的信息截到下面这张图里

         

    重要的信息都标注出来了,说明一下:

    ViewState和EventValidation可以通过http://www.testren.com/mylist.aspx?userid=2656967的请求页返回的html页面分析通过正则id=\"__VIEWSTATE\" value=\"(?<VIEWSTATE>.*?)\"和id=\"__EVENTVALIDATION\" value=\"(?<EVENTVALIDATION>.*?)\"获得,答案部分就需要我们自己去根据迭代的内容添加进去了,如果有20道题就要添加20个,相关的input标签的name可以参照上面用红色圈起来的部分,第1题的序号是从102开始,最后一题是102+19=121。其他的提交信息简单的处理办法就是照猫画虎,有样学样附加进去就得了。

    顺便用IEDeveloperToolbar确定一下,我们要找的ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$mylist$ctl21$selectRBL的位置(4个选项的name都是它,值就是1或者2,3,4),很稀饭IEDeveloperToolbar的这个Select Element by Click功能,给大家推荐一下。

    最后把返回页面里面的得分通过正则(\d{1,3})分过滤出来就可以了。

四、代码:

界面比较简单,提交后要过一会才能显示答案,另外有一点不好,就是网站会记录下你的迭代过程,其实作弊还是可以看得出来的)。

另外一个比较重要的地方是为了保存一个统一的访问session,我们必须使用 CookieContainer cookie = new CookieContainer();来装载第一次访问产生的cookie,同时每次请求的时候都要附上这个CookieContainer

Code
 HttpWebRequest request = null;//http请求
        HttpWebResponse response = null;//http响应
        StreamReader reader;//文本流读取器
        CookieContainer cookie = new CookieContainer();//非常重要的一个变量,通过cookie保存session状态

        
int count, maxPoint, point;//题目数量,最大分数,当前分数
        int[] choice;//保存答案的数组
        string url, postData, postDataTemplate, responseString;
        
//url,要post的数据,postdata模板(每次测试提交的数据只要改一下模板里面内容就好了),请求返回的字符串

        
private void btnSubmit_Click(object sender, EventArgs e)
        
{
            Init();
//初始化count、maxPoint、postDataFinal等变量
            
//对每一道题进行循环
            for (int i = 0; i < count; i++)
            
{
                Test(i);
            }

            
//把答案显示到界面 
            this.txtResult.Text = "";
            
foreach (int var in choice)
            
{
                
this.txtResult.Text += Convert.ToChar(64+var);
            }


        }


        
/**//// <summary>
        
/// 测试
        
/// </summary>
        
/// <param name="no">第几题</param>

        private void Test(int no)
        
{
            
//恢复提交数据的模板,因为下面做了改动
            postData = postDataTemplate;
            
//对当前题目依次选择BCD看是否会获得更大的分数
            for (int bcd = 2; bcd <= 4; bcd++)
            
{
                
int temp = no + 2;//ctr的编号注意是从ctl02开始的
                string pattern = null;
                
//区分ctl01和ctl20,个位数要加0
                if (temp < 10)
                
{
                    pattern 
= HttpUtility.UrlEncode("$ctl0" + temp + "$selectRBL"+ "=";
                }

                
else
                
{
                    pattern 
= HttpUtility.UrlEncode("$ctl" + temp + "$selectRBL"+ "=";
                }

                pattern 
= @"(?<=" + pattern + @")\d";//前瞻正则
                
//根据选中的答案,更改postdata
                postData = RegexHelper.Replace(postData, bcd.ToString(), pattern);
                
//提交数据
                byte[] postDataBytes = System.Text.Encoding.Default.GetBytes(postData);
                request 
= (HttpWebRequest)WebRequest.Create(url);
                request.ContentType 
= "application/x-www-form-urlencoded";
                request.ContentLength 
= postDataBytes.Length;
                request.CookieContainer 
= cookie;//重要
                request.Method = "POST";
                
using (Stream stream = request.GetRequestStream())
                
{
                    stream.Write(postDataBytes, 
0, postDataBytes.Length);
                }

                response 
= (HttpWebResponse)request.GetResponse();
                
//用GB2312编码读取响应流如果你用的不是简体中文系统,请用Encoding.GetEncoding("GB2312")
                using (reader = new StreamReader(response.GetResponseStream(), Encoding.Default))
                
{
                    responseString 
= reader.ReadToEnd();
                }

                
//获取分数
                point = int.Parse(RegexHelper.GetMatch(responseString, @"(\d{1,3})分"));

                
if (point > maxPoint)
                
{
                    choice[no] 
= bcd;//保存答案
                    maxPoint = point;//保存最大分
                    postDataTemplate = postData; //更新postdata模板
                    return;
                }

            }


        }


        
/**//// <summary>
        
/// 初始化
        
/// </summary>

        private void Init()
        
{
            url 
= this.txtUrl.Text;
            request 
= (HttpWebRequest)WebRequest.Create(url);
            request.CookieContainer 
= cookie;//重要
            response = (HttpWebResponse)request.GetResponse();
            
using (reader = new StreamReader(response.GetResponseStream(), Encoding.Default))
            
{
                responseString 
= reader.ReadToEnd();

            }

            
//获取问题个数
            count = RegexHelper.GetMatchCount(responseString, @"(\d+)、");
            choice 
= new int[count];//当前选择
            
//把所有答案设置为a
            for (int i = 0; i < count; i++)
            
{
                choice[i] 
= 1;
            }

            
// 获取页面的 ViewState                
            string viewState = RegexHelper.GetMatch(responseString, "id=\"__VIEWSTATE\" value=\"(?<VIEWSTATE>.*?)\"");
            
// 获取页面的 EventValidation                
            string eventValidation = RegexHelper.GetMatch(responseString, "id=\"__EVENTVALIDATION\" value=\"(?<EVENTVALIDATION>.*?)\"");
            viewState 
= HttpUtility.UrlEncode(viewState);
            eventValidation 
= HttpUtility.UrlEncode(eventValidation);
            
//构造postDataTemplateTemplate
            postDataTemplate = "__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=" + viewState;
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$txtMsnUser"+ "=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$txtMsnPass"+ "=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$tbxAd"+ "=" + HttpUtility.UrlEncode("快来做关于我的测试题,看看你有多少了解我 http://szzhouke.testren.com", Encoding.Default);
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$nickNameTB"+ "=qq";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$EmailTB"+ "=qq@qq.com";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$MobileTB"+ "=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$locationTB"+ "=9";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$wordsTB"+ "=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$RightContent$RightBodyContent$myLog$Login1$UserName"+ "=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$RightContent$RightBodyContent$myLog$Login1$Password"+ "=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$RightContent$RightBodyContent$myLog$Login1$RememberMe"+ "=on";
            postDataTemplate 
+= "&__EVENTVALIDATION=" + eventValidation;
            postDataTemplate 
+= "&__VIEWSTATEENCRYPTED=";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$submitAnswerTB.x"+ "=76";
            postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$submitAnswerTB.y"+ "=17";
            
//给postDataTemplate附加答案
            for (int k = 0; k < count; k++)
            
{
                
int temp = k + 2;
                
if (temp < 10)
                
{
                    postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$mylist$ctl0" + temp + "$selectRBL"+ "=" + choice[k];
                }

                
else
                
{
                    postDataTemplate 
+= "&" + HttpUtility.UrlEncode("ctl00$ctl00$ctl00$MainContent$MainBodyContent$MainBodyContent$mylist$ctl" + temp + "$selectRBL"+ "=" + choice[k];
                }

            }

            
//提交数据
            byte[] postDataTemplateBytes = System.Text.Encoding.Default.GetBytes(postDataTemplate);
            request 
= (HttpWebRequest)WebRequest.Create(url);
            request.ContentType 
= "application/x-www-form-urlencoded";
            request.ContentLength 
= postDataTemplateBytes.Length;
            request.CookieContainer 
= cookie;//重要
            request.Method = "POST";
            
using (Stream stream = request.GetRequestStream())
            
{
                stream.Write(postDataTemplateBytes, 
0, postDataTemplateBytes.Length);
            }

            response 
= (HttpWebResponse)request.GetResponse();
            
using (reader = new StreamReader(response.GetResponseStream(), Encoding.Default))
            
{
                responseString 
= reader.ReadToEnd();
            }

            
//获取最大分数
            maxPoint = int.Parse(RegexHelper.GetMatch(responseString, @"(\d{1,3})分"));
        }

 

相关代码下载

最后借助这个小工具把mm的题目答案都弄下来了,假装不经意的告诉她的时候,收到两个字答复,乖乖!(相信在南京呆过的人都会会心一笑)。估计有人会8一下问我后来怎么样了,后来只能说无疾而终,据说她和男朋友去了距离天堂最近的地方巴厘岛旅游后就分手了。呵呵,如果是你的话会继续追她吗?感情真的是一种很奇怪的东东~~

ps:如果你也有和技术有关的感情故事,欢迎你也来晒一下啊 呵呵

转载于:https://www.cnblogs.com/szzhouke/archive/2008/01/03/1023887.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值