一次爬方正教务处的成功实践

前戏

不知道从什么时候开始,搞教务处已经成了我山CS专业的学生学习一门新的WEB语言(只要跟web沾边的) Java PHP Python NodeJS Golang....等不同版本就这样一一诞生,当然 我也不例外 这次用golang实现模拟登陆教务处并获取课表 成绩等信息。(额 问我为什么喜欢搞教务处 大概是因为教务处的页面实在太丑了 然后每次都要我去评教 评教的Button ,Chrome竟然不兼容!这么烂的东西,评你【友善度】个【友善度】啊!

入戏

其实 去年自学PHP cURL的时候 我也试过模拟登陆教务处 那时候还做了个查分数的模块挂在微信上(但是人一多真的会炸啊2333 因为那时候服务器还在HK 所以被别人吐槽慢的跟什么一样了) 去年的时候 是看着这篇PHP解决方案来一步步操作的 虽然也遇到了一些问题 但是自己都解决啦~~

我还记得 那篇部落格里有一句话简直就像一个Flag一样 插在了那里 我当时看的时候就觉得药丸,药丸。。。。

好吧,这只是正方,如果在服务器后台加一个判断,如果验证码为空,直接返回登陆失败了!!!黑线!!!GG 了。。。

然后。。。

然后。。。

然后。。。

flag

正方的程序猿肯定也看到了这篇部落格(嗯 肯定是这样!)

怪不得 寒假老是接到小伙伴的反馈 说我的东西崩掉了(原来真的是这样)

所以,还是用通用办法(我连验证码一起抓还不行吗!)吧。。

HOW TO DO

我尽量说一下通用步骤:

STEP 1

请求还是要发的,第一步要去教务处的Login界面 去拿VIEWSTATE 和 VIEWSTATEGENERATOR,这两货我就不多说了,之前的链接里面有说明。还多了一步,就是这个操作也要拿下Cookie(STEP2要用到)

STEP 2

竟然验证码已经绕不过去了 那我们就不绕了。我们通过F12检查发现 验证码也是有地址的(./CheckCode.aspx),我们把Step1拿到的cookies带上去发Get请求到这个地址,不要废话,拿了Body体就走,然后把body里面的gif缓存在本地。这边给下示范:

// 获取验证码
var verify_code string
for {
//用刚才生成的cookie去爬 验证码   否则会504!!!!!

   res, _ = c.Do(req)      
   file, _ := os.Create("verify.gif")
   io.Copy(file, res.Body)

  fmt.Println("请查看verify.gif, 然后输入验证码, 看不清输入0重新获取验证码")
   fmt.Scanf("%s", &verify_code)
   if verify_code != "0" {
       break
   }

当然 我用了带break的while(true){}循环 憋说了 已经因为l1不分被嘲笑了无数次了(泪)

STEP3:

在STEP2确认测试通过的前提下,也就是本地存在了那张gif图片(测试的时候gif图片我是用ie打开的,因为读写要尽可能分离),接下来就是比较重要的post环节了,其实上面那篇php的实现里面已经写得很详细了,我这边由于是golang版本的,golang 1.5 新加了跟python一样的cookiejar .Client带cookiejar实现抓取实在是太爽了,蛤蛤蛤。。哦,对了,强调一点,由于这破JWC看起来像是上世纪的产物,所以,不要忘了把你的utf-8转成gbk2312哦,这个是个坑,勿入~

golang的话 可以考虑一下这个库

"github.com/scbizu/mahonia"

当然 七牛的库也不错

"github.com/qiniu/iconv"

其他的lang乃们就自己找吧(吐舌头~

这里我也贴个代码吧~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
*模拟post表单
*/
func post(Rurl string,c *http.Client,username string,password string,verify_code string,VIEWSTATE string,VIEWSTATEGENERATOR string,temp_cookies []*http.Cookie) []*http.Cookie{
postValue:=url.Values{}
cd:=mahonia.NewEncoder("gb2312")
rb:=cd.ConvertString("学生")
//准备POST的数据
postValue.Add("txtUserName",username)
postValue.Add("TextBox2",password)
postValue.Add("txtSecretCode",verify_code)
postValue.Add("__VIEWSTATE",VIEWSTATE)
postValue.Add("__VIEWSTATEGENERATOR",VIEWSTATEGENERATOR)
postValue.Add("Button1","")
postValue.Add("lbLanguage","")
postValue.Add("hidPdrs","")
postValue.Add("hidsc","")
postValue.Add("RadioButtonList1",rb)
//开始POST 这次POST到登陆界面 带上第一次请求的cookie 和 验证码 和 一些必要的数据
postUrl,_:=url.Parse(Rurl)
Jar,_:=cookiejar.New(nil)
Jar.SetCookies(postUrl,temp_cookies)
c.Jar=Jar
resp,_:=c.PostForm(Rurl,postValue)
cookies:=resp.Cookies()
return cookies
}

STEP4:

看到这里说明你已经快接近成功了。

拿着上面登陆成功的cookie去登陆成功的页面(./xs_main.aspx?xh=YOUR STUDENT No.)看看 是否能出现意料之中的body 没有的话 再仔细检查一下自己的STEP3 慢慢来 不要急 喝杯水 继续呗~

成功了的话 也不要以为JWC就是任你行了 Naive 还是有坑的。。。

如果 有一定web基础的同学肯定按下了F12 然后打开个人课表。没错,所以你看到了下面的页面其实都是假象(

没错 就是它(./xskbcx.aspx?xh=YOUR STUDENT No.&xm=urlencode(YOUR NAME)&gnmkdm=N121603)

其实,老司机告诉你,其实xm和gnmkdm都是可选的get set value 你只要get上去你自己的xh就可以了

Like this : ./xskbcx.aspx?xh=YOUR STUDENT No

STEP5:

如果泥还看下去,说明你遇到问题了 是不是发现Get上去了 却response给了你302啊 嘿嘿嘿 就是这个神奇的302的,

这时候查看header里的Location还是空,是不是感觉整个人都要崩溃了,我在这里也懵逼了一个晚上+一个上午

直到........

一个苹果掉在了我的头上。。。。

怎么可能 我又不是牛顿。。。

我偶然间 对比了两次request头

来,我们来看看:

norefer hasrefer

可以 很清楚的看到 不是cookie的锅(把你的光标从post函数上离开)

200的尝试 有referer头!

就是因为这个重定向头 导致你一直302;

此时 仿佛中了500w一般开心吧~

知道了这个梗 我们在Request里面设置一个重定向:

Like this:

1
req.Header.Set("Referer",courseURL)

STEP 6:

好了 JWC可以任你行了 去玩吧~ Enjoy your time,guys!

END

最后 贴上源码地址:https://github.com/scbizu/Zafu_jwcInterface

萌新 弱弱地求一发Follow(Star就算了 受不起)