Golang-自動化監控教務系統成績單

賜我白日夢發表於2020-06-02

一、Golang模擬使用者登陸,突破教務系統

1.1 請求登陸頁面

整個流程中的第一步是獲取登陸頁面,就像下圖這樣人為的通過瀏覽器訪問服務端,服務端返回反饋返回登陸頁面

image-20200602062729513

訪問登陸頁面的目的上圖中標註出來了,為了獲取到Cookie,給真正發起登陸到請求方法使用。

下面的golang傳送http到get請求,獲取登陸頁面的程式碼:

// 訪問登陸也,獲取cookie
func GetCookieFromLoginhtml(url string) (cookie string, e error) {
   res, err := http.Get(url)
   if err != nil {
   	e = err
   }
   // 獲取cookie
   cookie = res.Header.Get("Set-Cookie")
   cookie = util.GetOneValueByPrefixAndSurfix("JSESSIONID=", "; Path=/", cookie)
   res.Body.Close()
   return
}

1.2 抓包分析登陸請求

輸入賬號賬號密碼後點選登陸,將向後端傳送登陸請求,如下圖:

image-20200602063307341

分析向後端傳送到登陸請求都攜帶了哪些請求引數,攜帶了哪些請求頭資訊,以及需要通過Content-Type判斷,該如何處理form表單中的資料傳送到後臺。後臺才能正常響應。

image-20200602064317230

在瀏覽器的控制檯中我們可以去看下登陸頁面原始碼

image-20200602065641448

登陸頁面對應的js原始碼

image-20200602070318841

1.3 golang使用js引擎合成salt

這一步也是必須的,所謂獲取salt,其實就是通過golang使用js引擎執行encodeInp(xxx), 這樣我們才能得到經過加密後的username和password,進一步獲取到encoded

import (
	"github.com/robertkrimen/otto"
	"io/ioutil"
)
func EncodeInp(input string)(result string,e error)  {
	jsfile := "js/encodeUriJs.js"
	bytes, err := ioutil.ReadFile(jsfile)
	if err != nil {
		e = err
	}
	vm := otto.New()
	_, err = vm.Run(string(bytes))
	if err != nil {
		e = err
	}
	enc,err :=vm.Call("encodeInp",nil,input)
	if err != nil {
		e = err
	}
	result = enc.String()
	return
}

js部分的程式碼就不往外貼了,可以去下面的github地址中獲取

1.4 模擬表單提交,完成登陸

使用golang模擬登陸請求

// 模擬登陸
func login(salt, cookie string) (html string) {
	
	req, err := http.NewRequest("POST", LoginUrl, strings.NewReader("encoded="+salt))
  
	// 新增請求頭
	req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36")
	req.Header.Add("Cookie", "JSESSIONID="+cookie)
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")

	//傳送請求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("無密版qlu教務系統登陸請求失敗 : %v", err)
		return
	}
	// todo 根據狀態碼判斷下一步如何操作,如果狀態碼是302,表示操作成功
	fmt.Println("resp.Status:  ", resp.Status)

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("error : %v", err)
		return
	}
	// 返回個人主頁的html
	html = string(b)
	// 手動關閉
	resp.Body.Close()
	return
}

這一步中值得注意的地方:

第一:我們傳送的請求的型別是POST請求

第二:我們應該如何處理form表單中的資料後,再傳送給後端,後端才能正常處理呢?

具體處理成什麼樣,是需要根據請求頭中的Content-Type決定的。

不知道大家知不知道常見的Content-Type的幾種型別:在form 表單中有一個屬性叫做 entype可以間接將資料處理成Content-Type指定資料格式, 比如我們可以像這樣設定:

  • enctype = text/plain 那麼form表單最終提交的格式就是: 用純文字的形式傳送。

  • enctype = application/x-www-form-urlencoded

    • 表單中的enctype值如果不設定,則預設是application/x-www-form-urlencoded,它會將表單中的資料變為鍵值對的形式。
    • 如果action為get,則將表單資料編碼為(name1=value1&name2=value2…),然後把這個字串加到url後面,中間用?分隔。
    • 如果action為post,瀏覽器把form資料封裝到http body中,然後傳送到伺服器。
  • enctype = mutipart/form-data

    • 上傳的是非文字內容,比如是個圖片,檔案,mp3。

根據這個知識點,結合我們當前的情況,method=post,Content-Type = application/x-www-form-urlencoded

所以,在選擇golang的api時,我們選擇下圖這個api使用

image-20200602073500224

1.5 進入成績查詢頁,解析使用者成績

如果不出意外,經過上面的處理,我們已經完成登陸,並且獲取到後臺頁面的html原始碼了。

再之後我們就直奔成績查詢模組,還是使用如何的分析思路

func getAllScore(stuIdentify, cookie string) ([]mtStruct.Score, error) {
	// 傳送查詢成績的請求
	u := "http://jwxt.qlu.edu.cn/jsxsd/kscj/cjcx_list"
	req, err := http.NewRequest("POST", u, strings.NewReader("kksj=&kcxz=&kcmc=&xsfs=all"))
	if err != nil {
		fmt.Printf("error : %v", err)
		return nil, err
	}
	req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36")
	req.Header.Add("Cookie", "JSESSIONID="+cookie)
	req.Header.Add("Referer", "http://jwxt.qlu.edu.cn/jsxsd/kscj/cjcx_query?Ves632DSdyV=NEW_XSD_XJCJ")
	req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*;q=0.8,application/signed-exchange;v=b3;q=0.9")

	client := &http.Client{}
	resp, err := client.Do(req)
  ...
  
}

程式碼詳情可以去github上檢視。

二、植入微信公共號後臺

上面的功能實現後再結合Golang開發微信公眾號就能實現一款好玩的應用。

讓使用者通過微信公共號平臺和後端進行資料的互動,我們獲取到使用者的資訊,拿著使用者的資訊幫使用者監聽教務系統的成績單的狀態。一旦有成績第一時間推送給使用者。

點選檢視公眾號端設計思路


專案GitHub地址:https://github.com/zhuchangwu/golang-wechat-backend

相關文章