教务网的那点事儿

前言

一直对爬虫比较感兴趣,使用php写过一些小爬虫,爬过很多网站,然后收集有用的信息。php的curl库是一个很好用的工具,用来模拟请求爬取网页还是很方便的,使用方法也很简单。然后配上simple_html_dom,一个html的解析插件,一些简单的网页爬取工作就已经可以胜任了。后来发现python更适合来写爬虫,因为python拥有很多强大的库,借用网上的一些话: > 1.python 支持多线程,多进程(fork/deamon); > > 2.python有丰富的异步模块、分析模块、爬虫模块以及爬虫相关的资料等等等等;

下面是一个简单的get请求:

  • php使用curl

    $ch = curl_init();
    curl_setopt($ch,CURLOPT_REFERER,$url);
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
    $data = curl_exec($ch);
    
  • python使用requests库

    import requests
    html = requests.get(url)
    print(html.text)
    

看起来,python代码比起php的就简洁一些。另外,本文的代码使用的php版本为7.+,python版本为3.5+。

那接下来就进入正题吧。

简介

本文使用php代码完整地讲诉如何一步步模拟登录教务网,然后取得课表等信息,使用python原理其实也都是一样的,只是对应的方法的具体实现不一样。php代码和python代码最后都会在结尾放出来。使用php而不是python的原因是,最初使用php实现登录的,python是后来自己根据php代码的原理移植的,总之原理都是差不多的。另外,这是我第一次在简书上写文章,介于水平有限,有错之处还望指正。

正文

这应该是最重要的一步了。我们知道,成功登录教务网后肯定是会返回一个cookie的,我们要做的就是,成功登录教务网,然后储存返回的cookie,再利用这个cookie去访问其他的链接。只要正确地得到了这个cookie,那就成功一大半了。下面就是详细地步骤: 1. 获取登录url 首先,打开谷歌浏览器,进入教务网首页,F12打开开发者工具,勾上Preserve log防止链接跳转找不到;然后输入正确的学号密码,于是成功得到了登录url:

2. 获取请求参数:

其中,最重要的前五个参数和最后一个参数,然后最难的就是获取第一个,第二个,以及最后一个参数了,下面就一一讲解每个参数的获取。

既然是通过表单提交的,又不是我们自己输入的,那就右键打开查看网页源代码吧。 于是乎找了半天,什么鬼,居然没找到?想了想,直接用get请求一下登录链接,然后把返回数据写入html文件中,找到里面的form标签,可以看到所有的参数都在里面,其中重要的代码: <input name="__VIEWSTATE" type="hidden" value="*****",这就是那一串非常长非常蛋疼的参数,先放着,继续找; <input name="__VIEWSTATEGENERATOR" type="hidden" value="CAA0A5A7"/>第二个参数也找到了; <input id="efdfdfuuyyuuckjg" name="efdfdfuuyyuuckjg" type="hidden"/>,最后一个找是找到了,但是我要的value呢?这… 在最初的时候,这里困扰了我很长一段时间,导致我一直无法成功地登录,直到后来灵机一动,好吧,其实是听室友,成功模拟登录了的,说这是经过加密了参数。然后我突然醒悟了过来,于是,与教务网的斗争继续。 前端加密无非就是js了,寻找js,然后搜索有关“efdfdfuuyyuuckjg”的代码。按照这个思路,终于找了了其加密函数。其实就在返回的html数据中。其中有这么一段js代码:

function chkpwd(obj) {
    var schoolcode = "10611";
    var yhm = document.all.txt_dsdsdsdjkjkjc.value;
    if (obj.value != "") {
        if (document.all.Sel_Type.value == "ADM") yhm = yhm.toUpperCase();
        var s = md5(yhm + md5(obj.value).substring(0, 30).toUpperCase() + schoolcode).substring(0, 30).toUpperCase();
        document.all.efdfdfuuyyuuckjg.value = s;
    } else {
        document.all.efdfdfuuyyuuckjg.value = obj.value;
    }
}

结合表单中的

<input id="efdfdfuuyyuuckjg" name="efdfdfuuyyuuckjg" type="hidden"/>

最后一个参数也就显而易见了。js加密过程如下: 1)将密码md5加密,然后截取前30个字符,并且变成大写字母; 2)将学号与第一步得到的字符串拼接,再与固定参数拼接,然后将整个字符串md5加密,截取前30个字母并且转为大写,就得到了加密过后的字符串,也就是input的value值。 既然得到了加密过程,那用php代码就很好实现了,代码如下:

function checkPwd($code, $pwd, $schoolcode) {
     return strtoupper(substr(md5(($code . strtoupper(substr(md5($pwd), 0, 30)) . $schoolcode)), 0, 30));
}

而第一个和第二个参数直接正则匹配出来就行了,代码如下:

function getView() {
        $url     = $this->login_url;
        $result  = $this->get($url);
        $pattern = '/<input type="hidden" name="__VIEWSTATE" value="(.*?)" \/>/is';
        preg_match_all($pattern, $result, $matches);
        $res[0]  = $matches[1][0];
        $pattern = '/<input type="hidden" name="__VIEWSTATEGENERATOR" value="(.*?)" \/>/is';
        preg_match_all($pattern, $result, $matches);
        $res[1] = $matches[1][0];
        return $res;
}

返回的数组就是两个参数的值。

请求结果

这样我们所有的参数都得到了,直接post带参数,得到返回数据,代码如下:

function post($url, $post_data) {
        $this->cookie = dirname(__FILE__) . '\cookie_edu.txt';
        $ch           = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookie);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
}

返回html界面

OK,登录成功。而且cookie我们也保存下来了。 那么在我们检测是否成功登录的时候,使用strpos函数检测返回的字符串中是否含有“正在加载权限数据”字符串就可以了,该函数返回出现该字符串的位置,若没有待检测字符串返回-1。

既然得到了cookie就好办了,直接抓取如成绩查询的url然后携带cookie去请求就行了,不管是get或者post都是可以的。比如get:

function get($url) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookie);
        $result = curl_exec($ch);
        return $result;
}

试着抓取一下考试安排:

得到了下面的页面,注意这些url都可以F12抓包得到的,其它如获取成绩啊什么道理也是一样的,只要找到url,携带好cookie请求就可以了。

结语

整个过程基本就是这样了,其实有关模拟登陆步骤都是差不多的,只不过有的可能有验证码,有的加密过程更加复杂,比如腾讯的登陆加密过程实现是相当复杂,以前研究过不久就望而却步了。不过网上还是有大牛弄出来的。所以学习实在是无止境的,而自己要学的东西还有很多很多。

仓库地址:https://github.com/long2ice/edu.git