php模拟登陆青果教务系统

注:本篇文章原先放在旧服务器blog.summerpro.cn上,由于服务器停用,现将文章放在这里,欢迎大家阅读以及批评指正。

这是博主去年暑假的时候搞过的,当时是想要做微信公众号上的查成绩功能,由于学习方式不太合理,一开始就没完全搞清楚session的问题,走了很多弯路,花了不少时间,今天趁十一国庆不想复习的空子把它写到博客上与大家分享一下~

读这篇博客之前希望大家能够先了解下面几个小知识,这样对做网络爬虫分析大有好处,而且可以少走很多弯路:

1、http协议,这个是基本的知识点,网上资料很多,需要大家了解http的请求头与响应头的内容所代表的含义以及功能,还有是在一次通过浏览器访问网页的过程中,对其内部工作过程有一个清晰的认识,我这里就简单用文字描述一下,当用户打开浏览器,输入一个网址并回车的时候,浏览器先是通过域名服务器获得该网址的ip,然后向目标ip发出请求信息,请求方式最常用的就是post以及get方式,里面包含浏览器类型,编码方式,cookie以及表单信息等等,目标服务器收到后,由Apache,IIS,nginx等服务器软件进行处理,如果请求目标页面是静态的,那么服务器会直接将响应页面加上响应头发送回客户端,如果是动态的,服务器会先将目标页面通过php,java等后端程序运行,将运行结果作为响应内容发送回客户端。

2、session的工作机制,,session保存于服务器,是用来区分不同用户的,同时还可以保存一些用户的信息,一般在一次会话中用户第一次访问时,服务器会生成一个session的id与该用户对应,然后将这个id以cookie的形式发回到客户端(如果是web,那客户端就是浏览器),之后用户在一次会话过程中对该网站的每次点击都会以cookie的形式带着这个session id,以表示这是哪个用户,例如是在有用户登录的网站中session的作用非常明显,用户登录后的进一步访问,服务器端需要判断是哪个用户,就需要用session来验明身份,这里分享一个网友写的文章链接http://justsee.iteye.com/blog/1570652关于session的工作机制写的非常生动!

3、然后大家需要了解搞模拟登陆的基本套路,本质来讲,模拟登陆就是通过机器模仿用户使用浏览器访问网页的行为从而实现自动处理的能力,从理论上来讲,只要是能够在网页上看到的东西,模拟登陆都可以得到,甚至用户看不到的东西,通过合理分析,我们也可以通过程序获取到。所以,我们的套路本质就是把整个通过浏览器访问的过程用程序模拟出来,由于是模拟登陆,一般都会用到cookie和session,我们第一步是先访问该网站的首页或者登陆页面甚至是随意一个页面都可以,这个时候服务器端会生成一个session,然后以cookie的形式返回给我们,我们得到这个session,就相当于拥有了这个网站的会员卡,然后我们带上这个会员卡,再加上登陆信息(比如用户名,密码,验证码之类)以表单的形式发给登陆处理的后台页面,验证通过后,服务器会在这个session对象中标记登陆成功之类的(这属于是网站开发者自己用程序实现的而不是服务器自动实现),之后我们就可以带着这个会员卡去访问登陆后的其他页面了,这个是基本的套路,当然具体情况要具体分析,有反爬虫策略的网站会有很多检验机制阻止我们去模拟这个过程,其实就是通过增加登录过程的复杂性来达到目的的,例如增加验证页面,加密数据,验证http的头文件是否正常。

4、第四条比较容易,需要大家知道如何使用浏览器中的F12键,也叫开发者模式,这是浏览器自带的抓包工具,我比较推荐火狐和Google浏览器,当然也可以用fiddler之类的专门的抓包软件。我常用火狐的开发者模式,里面除了可以进行抓包,还可以进行前端代码的断点调试,界面设计辅助等非常方便的功能,具体的我就不写了,太多了,大家可以去查一下教程。

5、最后呢,需要大家知道php进行模拟登陆时候用到的接口,我后面都是用php自带的curl来写的。下面我就给几个常用函数。

$ch = curl_init();  //初始化
 curl_setopt($ch, CURLOPT_URL, "http://localhost/mytest/phpinfo.php");  //设置访问地址
 curl_setopt($ch, CURLOPT_HEADER, false);  //false代表响应内容中不显示头信息
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //如果把这行注释掉的话,就会直接输出响应信息  
 $result=curl_exec($ch);  //开始执行,响应内容以字符串的形式赋值到$result中
 curl_close($ch);  //结束


下面我们就开始分析了!

1、拿我们学校的教务系统作例子,我在访问网站首页http://210.42.72.73:888/jwweb/的时候进行抓包,下面这是第一个页面的信息,可以看到请求头开始还没有cookie,响应头将session的id以cookie的形式送了回来,而我们要的就是这个session。




2、我们从首页点击到登录页面http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx,随便输入登录信息,然后查看其产生的表单的内容:



我们发现其内容远比我们想象的要复杂,这个时候我们要尽量弄清各项关键数据的作用以及产生方式,这也是做模拟登陆麻烦的地方,这些我们都可以通过页面响应内容进行合理的分析来得到答案。我们看一下响应页面http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx:

可以看出,__VIEWSTATE是一开始就有了的,这说明它是服务器端就已经生成了的,而下面的pcInfo,typeName,fgfggfdgtyuuyyuuckjg,dsdsdsdsdxcxdfgfg,是空的,而在上面的截图中它又存在,说明他们是通过js及时生成的,其生成方式也可以找到。剩下的几个数据也是类似方法,我们都可以找出他们的来源,这里就不一一列出。

<input type="hidden" name="__VIEWSTATE" value="dDw4ODEwMTkyNTY7Oz4d/KVREudotyCvK97yI+j4oRZrBw==" />

<input id="pcInfo" type="hidden" name="pcInfo">
<input id="typeName" type="hidden" name="typeName">
<input type="hidden" id="dsdsdsdsdxcxdfgfg" name="dsdsdsdsdxcxdfgfg">
<input type="hidden" id="fgfggfdgtyuuyyuuckjg" name="fgfggfdgtyuuyyuuckjg">

function chkpwd(obj) {
    if (obj.value != '') {
        var s = md5(document.all.txt_asmcdefsddsd.value + md5(obj.value).substring(0, 30).toUpperCase() + '11072').substring(0, 30).toUpperCase();
        document.all.dsdsdsdsdxcxdfgfg.value = s;
    } else {
        document.all.dsdsdsdsdxcxdfgfg.value = obj.value;
    }
}
function chkyzm(obj) {
    if (obj.value != '') {
        var s = md5(md5(obj.value.toUpperCase()).substring(0, 30).toUpperCase() + '11072').substring(0, 30).toUpperCase();
        document.all.fgfggfdgtyuuyyuuckjg.value = s;
    } else {
        document.all.fgfggfdgtyuuyyuuckjg.value = obj.value.toUpperCase();
    }
}


上面的函数是将我们输入的验证码以及密码进行加密,只可惜由于前端代码的透明性,其加密方式都可以看到。

3、通过分析,我们得出,在进行模拟提交表单的时候我们一定需要先访问http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx来获得__VIEWSTATE这个值,然后再把其他值模仿js函数进行生成,一股脑儿进行提交,哦对了!一开始我们还得先得到session,不过就像我前面说的,访问任意一个该网站页面都可以获得session,因此我们只需要访问/_data/index_LOGIN.aspx这个页面就可以同时得到session和__VIEWSTATE了。

4、差点忘了一个重要的东西,验证码!在没有验证码自动识别的情况下,我们需要在手动输入验证码之后才能进行提交,那我们还需要带着session去访问生成验证码的页面得到验证码,哎,真是麻烦(写博客打字真麻烦)。我的想法是自己写一个a.php页面,这个页面专门访问教务系统的验证码页面,然后生成图片,再从我的主页面index.php调用a.php得到图片,不过a.php需要带着session去访问,于是我就在index.php页面先去访问/_data/index_LOGIN.aspx,得到session后将其存储在我自己的服务器的session中,然后a.php再去调用我自己的session从而获得教务系统的session。这样的想法怎么想都没问题,但在实际操作中却发现登录成功的概率非常不稳定,经常会失败,后来我想到有时候通过浏览器正常登录教务系统时在网络状态不好的情况下也会出现登录失败,会不会是跟请求验证码页面以及请求/_data/index_LOGIN.aspx之间的时间延迟有关??然后我做了一个实验,通过抓包软件进行网络数据的拦截,在我通过浏览器访问登录页面时浏览器会同时区请求/_data/index_LOGIN.aspx和/sys/ValidateCode.aspx验证码页面,我阻止了后者的请求一小会儿,然后再允许这个请求,相当于做了一个时间的延迟,果然,登录失败了!青果居然利用两个页面的请求时间差来做反爬验证,终于,识破了青果的诡计,哈哈!最后我把对两个页面的请求都放到了我的a.php页面中,在我的index.php主页面不进行任何模拟请求,只是会调用a.php,下面是我的a.php的代码:

session_start();
//$_SESSION['cookie_jar']=$cookie_jar;
$ch = curl_init();
$header[]="User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0";
$header[]="Cache-Control: max-age=0";	
$header[]="Connection: keep-alive";
$header[]="Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; 
$header[]="Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3";
$header[]="Host:210.42.72.73:888";	  
curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
curl_setopt($ch, CURLOPT_URL, "http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx");
curl_setopt($ch,CURLOPT_VERBOSE,1);
curl_setopt($ch, CURLOPT_HEADER,true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
$filecontent=curl_exec($ch);
//echo $filecontent;
preg_match('/Set-Cookie:(.*);/iU',$filecontent,$str); //正则匹配
$cookie = $str[1]; //获得COOKIE(SESSIONID)
$_SESSION['cookie']=$cookie;
preg_match('/<input type=\"hidden\" name=\"__VIEWSTATE\" value=\"(.*)\"/iU',$filecontent,$str);
$__VIEWSTATE=$str[1];
$_SESSION['__VIEWSTATE']=$str[1];


$ch = curl_init();
$header=array();
$header[]="User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0";
$header[]="Referer:http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx";	 
$header[]="Host:210.42.72.73:888";	  
//$header[]="Cache-Control: max-age=0";	
$header[]="Connection: keep-alive";
$header[]="Accept:image/png,image/*;q=0.8,*/*;q=0.5"; 
$header[]="Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3";
curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
curl_setopt($ch, CURLOPT_URL, "http://210.42.72.73:888/jwweb/sys/ValidateCode.aspx");
curl_setopt($ch,CURLOPT_VERBOSE,1);
curl_setopt($ch, CURLOPT_HEADER,false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
//echo $cookie;
$filecontent=curl_exec($ch);
echo $filecontent;


那么这个页面得到的便是验证码图片了,同时还将__VIEWSTATE和教务系统的session存到我自己的session中,方便后面模拟提交表单。

5、这下我们通过手动输入验证码后就可以模拟提交了,直接看代码:


$id="学号";
$pwd="密码";
$code=@$_POST['code'];
$cookie=@$_SESSION['cookie']; 
$referer="http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx";
$a=strtoupper(substr(md5($pwd),0,30));
$dsdsdsdsdxcxdfgfg=strtoupper(substr(md5($id.$a."11072"),0,30));//模拟前面js的加密
//11072是学校代码,每个学校都不一样
	
$b=strtoupper(substr(md5(strtoupper($code)),0,30));
$fgfggfdgtyuuyyuuckjg=strtoupper(substr(md5($b."11072"),0,30));

$pcInfo="Mozilla/5.0+(Windows+NT+6.1;+WOW64;+rv:45.0)+Gecko/20100101+Firefox/45.0Windows+NT+6.1;+WOW645.0+(Windows)+SN:NULL";
$__VIEWSTATE=$_SESSION['__VIEWSTATE'];
        
$data = array (
    'fgfggfdgtyuuyyuuckjg'=>$fgfggfdgtyuuyyuuckjg,
    'dsdsdsdsdxcxdfgfg'=>$dsdsdsdsdxcxdfgfg,
    'txt_asmcdefsddsd' => $id, 
    'txt_pewerwedsdfsdff' => '',
    'txt_sdertfgsadscxcadsads'=>'',
    'typeName' => iconv("UTF-8","GB2312//IGNORE","学生"),
    'sbtState'=>'',
    'Sel_Type'=>'STU',
    'pcInfo'=>$pcInfo,
    '__VIEWSTATE'=>$__VIEWSTATE
); 
$data = http_build_query($data);
$header=array();
$header[]="User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0";
$header[]="Host:210.42.72.73:888";
$header[]="Referer:http://210.42.72.73:888/jwweb/_data/index_LOGIN.aspx";
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $referer); 

curl_setopt($ch,CURLOPT_HTTPHEADER,$header);//设置请求头,青果会通过请求头来验证请求是否为爬虫
 
curl_setopt ( $ch, CURLOPT_POST, 1 );//请求方式为post
curl_setopt($ch, CURLOPT_HEADER, true); //返回结果带头信息
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER,true);
curl_setopt($ch, CURLOPT_TIMEOUT,30); 
curl_setopt($ch, CURLOPT_COOKIE, $cookie); //带上session值
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );//写入post信息
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1); 
$filecontent=curl_exec($ch);



然后我们查看响应文件内容,发现它会自动跳转到登陆成功的页面http://210.42.72.73:888/jwweb/MAINFRM.aspx,这说明我们模拟登陆成功了!

6、到这里我们已经基本无压力了,无非就是模拟查看成绩,查看课表的操作,我们通过抓包,可以看出是通过向/xscj/Stu_MyScore_rpt.aspx这个页面发送post请求(里面写输出格式之类的参数),从响应你内容中我们可以得到成绩的图片地址,然后我们再去get请求/xscj/Stu_MyScore_Drawimg.aspx就可以了,这个页面里面是图片格式的成绩。


大功告成!!!呼呼!写到这真是累,一不小心就写了这么多内容。。

下面贴出我的小网页,嘿嘿!

             





----------------------更新于2016.12.21--------------------------------------

由于很多网友都问我关于模拟登陆青果的问题,我现在把一些问题补充写在这里,希望大家都能理解其中的原理。

1、关于青果通过两个页面的时间延迟来反爬虫的问题

想象一下,假如我们按照我最开始的做法,将模拟访问青果的index_LOGIN.asp的过程放到index.php中,将访问验证码的页面放到a.php,用户通过浏览器先是访问我们的index.php的时候,浏览器向我们的服务器发了一个请求,这个时候服务器先是运行index.php里面的程序,程序中的curl函数向青果的index_LOGIN.asp发出模拟请求得到session,然后我们的服务器将运行结果响应发回浏览器,这个时候浏览器再通过dom解析出html中的内容,其中有一项是<img src="a.php">,浏览器会向我们的服务器再次发出一个请求希望得到a.php的响应,然后a.php会通过curl函数向青果服务器请求ValidateCode.aspx页面,最终a.php将收到的来自ValidateCode.aspx响应,然后返回给客户端浏览器,在这整个过程中浏览器为了成功登陆青果,所有的过程都要先经过我们的服务器的中转,就类似于代理服务器一样。

而用户直接访问青果教务系统的时候会怎么样呢?浏览器先是对index_LOGIN.asp页面发出请求,青果服务器发回响应,然后浏览器再对验证码页面ValidateCode.aspx发出请求,青果服务器再次发回响应。

很明显,我们做模拟登陆的时候会比正常登录网站花费更多的时间,除了路程的增加,还有中转服务器内程序运行的时间,利用这个来做反爬验证是再好不过了!

2、关于登录成功或者失败后有人会出现自动跳转到一个404页面

成功的话是MAINFRM.asp,失败的话叫做sorry.aspx吧好像,这是因为你把模拟登陆的响应内容输出了,在原来的青果系统中,在登录成功或者失败后会通过js来进行跳转到相关页面,因此如果我们把模拟登陆的代码输出时,它会被发送到浏览器,并用js执行,自然就跳转了,由于写的是本地跳转,所以是跳转到当前域名下的MAINFRM了,由于我们的服务器中并没有这个页面,因此就显示404了。


----------------------更新于2017.7.30--------------------------------------

现在将旧服务器上的网友评论放上来方便大家参考。












展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值