教务网的那点事儿
前言 一直对爬虫比较感兴趣,使用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; } } 结合表单中的 ...