今天天氣甚好,并且剛剛學會基本的nodejs爬蟲和抓包,然後就想着爬取學校的教務系統去嘗試着爬取成績。下面我為大家一一講解Nodejs模拟登入學校的教務系統+爬取頁面成績并進行解析。
知識和工具準備
① Nodejs的基本知識。
②Fiddler抓包工具的使用。
③request、cheerio第三方插件的使用。
第一步:模拟登入
就拿我們學校為例,先拿到了學校的無須驗證碼登入的url,其他讀者們,自己學校的話,可以通過fiddler抓包工具去抓包看看傳到登入接口的參數還有請求接口的方法。
先抓取發送到學校服務的包并進行解析
//我們學校的hostname位址以及端口、請求方式為http請求、請求登入的路徑、請求的方法、參數
const hostName = 'jwgl.just.edu.cn';
const port = 8080;
const path:'/jsxsd/xk/LoginToXk';
const method = "POST";
//傳遞的參數
USERNAME:"xxxx", //使用者的學号
PASSWORD:'xxxxx', //使用者的密碼
發送請求,并且根據傳回的内容進行是否登入成功進行判斷并進行内容的爬取和解析。
(所有的解釋直接看代碼中。)
const http = require('http');
const queryString = require('querystring');
const request = require('request');
const cheerio = require('cheerio');
const hostName = 'jwgl.just.edu.cn';
const port = 8080;
//将參數轉換成字元串
const postData = queryString.stringify({
USERNAME:"xxxxx",
PASSWORD:'xxxxx',
});
let cookieAll ;
//發送的請求的條件
let option = {
hostname:hostName,
method:"POST",
port:port,
path:'/jsxsd/xk/LoginToXk', //請求的路徑
//頭檔案的配置
headers:{
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData) //轉換成buffer和字元串的合并
}
};
//進行發送的請求
const req1 = http.request(option,(res)=>{
res.setEncoding('utf8'); //對傳回的字元串進行轉碼,轉換成utf8
console.log("相應頭部",res.headers);
console.log(res.headers.location);
//根據發送回來的資料,進行合并。
if(res.headers.location){
//解析并且合并cookie。
console.log(res.headers['set-cookie']);
let cookie = res.headers['set-cookie'];
let cookie1 = cookie[0].slice(0,cookie[0].indexOf(';'));
let cookie2 = cookie[1].slice(0,cookie[1].indexOf(';'));
cookieAll = cookie1+";"+cookie2;
console.log(cookieAll);
//解析結果在下方圖一
//用fiddler抓包抓取url并且進行分析在下方圖二
//擷取可選的查詢條件
request({
url:'http://jwgl.just.edu.cn:8080/jsxsd/kscj/cjcx_query?Ves632DSdyV=NEW_XSD_XJCJ',
method:'POST',
headers:{
'Content-Type':'application/x-www-form-urlencoded',
'Cookie': cookieAll,
}
},(err,red2,body)=>{
if(err){
console.log(err.message)
}else{
//這段代碼進行頁面的解析 解析過程和結果在圖三
// console.log(body);
let $ = cheerio.load(body);
let content = $('#kksj').children(); //#kksj為頁面中html中的選擇框的id
console.log("選項的長度為:",content.length);
console.log("原來的content:",content);
console.log("可選擇的學期:");
for(let i = 0;i<content.length;i++){
console.log(content[i].children[0].data)
}
}
});
//查詢成績的條件(學期) 傳遞的參數以及url進行抓包分析,在下方圖四
//查詢的條件
let Body = queryString.stringify({
kksj:'2018-2019-1', //查詢條件
kcxz:"",
kcmc:"",
xsfs:'all'
});
let options = {
method:'POST',
url:'http://'+hostName+":"+port+'/jsxsd/kscj/cjcx_list',
headers:{
'Content-Type':'application/x-www-form-urlencoded',
'Cookie': cookieAll, //攜帶cookie
'Content-Length':Body.length
},
};
console.log("options為",options);
//條件查詢成績的api
request({
method:'POST',
url:`http://${hostName}:${port}/jsxsd/kscj/cjcx_list?${Body}`,
headers:{
'Content-Type':'application/x-www-form-urlencoded',
'Cookie': cookieAll,
},
},(err,red,body)=>{
if(!err&&red.statusCode === 200){ //根據傳回的頁面進行爬取和解析資料在下方圖五
//console.log(body);
let $ = cheerio.load(body);
let content = $('#dataList tr');
//解析過程----
for(let i=1 ;i<content.length;i++){
console.log(
"課程号:"+content[i].children[5].children[0].data+" "+
"課程名稱:"+ content[i].children[7].children[0].data+" "+
"成績:"+content[i].children[9].children[0].data+" "+
"學分:"+content[i].children[11].children[0].data+""+
"總學時:"+content[i].children[13].children[0].data+""
)
}
}
})
}
res.on('data',(data)=>{
console.log(data)
});
res.on('end',()=>{
console.log("響應中已經沒有資料")
});
res.on("error",()=>{
console.log("錯誤的資訊",error.message)
})
});
req1.write(postData);
req1.end();
圖一:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9EFRPFTTq10MFRVT3V1MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2gTNzADO0YTM2ATNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
圖二:用fiddler抓包進入可選擇的條件進行抓取請求的url以及傳遞的參數
圖三:
html頁面解析中這個id中可選擇的text
解析并且循環列印出來的結果:
圖四:
分析url:
分析傳遞的參數:
圖五:
解析的頁面table
解析結果:
總結:
全部的過程到這就結束了,如何讀者需要在第三方軟體顯示的話,就可以寫一個接口然後傳回給前端,前端再進行解析并且顯示就完美了。
作者解析的是在傳回給微信小程式,在微信小程式中進行解析。如圖: