小爱课程表旧版正方教务系统适配
前言
之前有做过相关的课表网页解析,所以花费了一天时间完成了学校的课程表适配,因为小爱课程表和学校课程安排有些许从出入,所以尽可能保证展示的情况下完成了解析
观看本文章的前提是学习了解过前端开发知识,且了解小爱课程表的开发文档,开发规范:https://ldtu0m3md0.feishu.cn/docs/doccnhZPl8KnswEthRXUz8ivnhb
网页分析
因为学校教务系统采用旧版正方教务系统,所以我们直接登陆进课表页面分析网页代码,如下:
通过观察代码可以发现,班级课表内容是存在id=Table6的table标签下而个人课表是存在id=Table1的table标签下,所以我们选择采用scheduleHtmlParser返回的html来进行解析,于是,scheduleHtmlProvider这边我们直接清理掉相关代码即可:
scheduleHtmlProvider.js
function scheduleHtmlProvider(iframeContent = "", frameContent = "", dom = document) {
return dom.querySelector('#iframeautoheight').contentWindow.document.body.innerHTML;
}
解析课表代码
因为小爱课程表需要提供作息时间的数组,且课表中作息时间是固定写死的,于是我们手动写入time数据,顺带把最后需要的数据作为全局变量定义一下:
var time = [
{"section": 1,"startTime": "08:00","endTime": "08:50"},
{"section": 2,"startTime": "09:00","endTime": "9:50"},
{"section": 3,"startTime": "10:10","endTime": "11:00"},
{"section": 4,"startTime": "11:10","endTime": "12:00"},
{"section": 5,"startTime": "14:30","endTime": "15:20"},
{"section": 6,"startTime": "15:30","endTime": "16:20"},
{"section": 7,"startTime": "16:30","endTime": "17:20"},
{"section": 8,"startTime": "17:30","endTime": "18:20"},
{"section": 9,"startTime": "19:30","endTime": "20:20"},
{"section": 10,"startTime": "20:20","endTime": "21:30"},
]
var jsonArray = []
接下来我们通过cheerio
和jquery
解析table的内容并选择是班级课表还是个人课表,并通过两层for进行行和列的遍历,代码如下:
function scheduleHtmlParser(html) {
var $ = cheerio.load(html, { decodeEntities: false });
if ($("#Table6").length > 0) {//班级课表查询界面适配
$("#Table6 tr").each(
function (i) {
if (i > 1) {
$(this).children('td').each(function (j) {
if ((i - 1) == 3 || (i - 1) == 7) {
if (j > 0) {
console.log("第"+(i-1)+"节课,周"+(j)+"课程名称:"+$(this).html());
}
} else if ((i - 1) == 1 || (i - 1) == 5 || (i - 1) == 9) {
if ((j - 1) > 0) {
console.log("第"+(i-1)+"节课,周"+(j-1)+"课程名称:"+$(this).html());
}
}
})
}
}
)
}
else {//个人课表查询界面适配
$("#Table1 tr").each(
function (i) {
if (i > 1) {
$(this).children('td').each(function (j) {
if ((i - 1) == 3 || (i - 1) == 7) {
if (j > 0) {
console.log("第"+(i-1)+"节课,周"+(j)+"课程名称:"+$(this).html());
}
} else if ((i - 1) == 1 || (i - 1) == 5 || (i - 1) == 9) {
if ((j - 1) > 0) {
console.log("第"+(i-1)+"节课,周"+(j-1)+"课程名称:"+$(this).html());
}
}
})
}
}
)
}
var jsonArray1 = JSON.stringify(jsonArray);
var time1 = JSON.stringify(time);
var conss = new Object();
conss.courseInfos = JSON.parse(jsonArray1);
conss.sectionTimes = JSON.parse(time1);
var json2 = JSON.stringify(conss);
console.info(JSON.parse(json2));
return JSON.parse(json2);
}
这边我们成功拿到了课表信息后,通过人工分析,我们发现两个课表的适配页面的内容是不同的,于是我们分别写不同的方法去解决适配内容不同的问题,代码如下:
/**
得到单科课程信息(班级课表)
*/
function getClass(classHtml, day, section) {
var classA = [];
var classs = classHtml.split('<br>');
if (classs.length > 1) {//防止空课程
if (classs.length <= 6) {//当课程为标准课程
var classObj = {};
classObj.name = classs[0];
classObj.position = classs[3];
classObj.teacher = classs[2];
classObj.weeks = [].concat(getWeeks(classs[1]));
classObj.day = day;
classObj.sections = [];
classObj.sections.push(time[(section - 1)]);
classObj.sections.push(time[(section)]);
classA.push(classObj);
} else {//当课程为双课程
//第一节课
var classObj = {};
classObj.name = classs[0];
classObj.position = classs[3];
classObj.teacher = classs[2];
classObj.weeks = [].concat(getWeeks(classs[1]));
classObj.day = day;
classObj.sections = [];
classObj.sections.push(time[(section - 1)]);
classA.push(classObj);
//第二节课
if(classs[4].indexOf('调')!=-1){
var classObj1 = {};
classObj1.name = classs[7];
classObj1.position = classs[10];
classObj1.teacher = classs[9];
classObj1.weeks = [].concat(getWeeks(classs[8]));
classObj1.day = day;
classObj1.sections = [];
classObj1.sections.push(time[(section)]);
classA.push(classObj1);
}else{
var classObj1 = {};
classObj1.name = classs[6];
classObj1.position = classs[9];
classObj1.teacher = classs[8];
classObj1.weeks = [].concat(getWeeks(classs[7]));
classObj1.day = day;
classObj1.sections = [];
classObj1.sections.push(time[(section)]);
classA.push(classObj1);
}
}
}
return classA;
}
/**
周次解析(班级课表)
*/
function getWeeks(weeksHtml) {
var weeksStr = weeksHtml;
var weeksA = [];
if (weeksStr.indexOf('-') != -1) {
if (weeksStr.indexOf('单') != -1) {
var weeksA1 = weeksHtml.split('-');
for (var i = parseInt(weeksA1[0]); i <= parseInt(weeksA1[1]); i = i + 2) {
weeksA.push(i);
}
} else if (weeksStr.indexOf('双') != -1) {
var weeksA1 = weeksHtml.split('-');
for (var i = parseInt(weeksA1[0]); i <= parseInt(weeksA1[1]); i = i + 2) {
weeksA.push(i);
}
} else {
var weeksA1 = weeksHtml.split('-');
for (var i = parseInt(weeksA1[0]); i <= parseInt(weeksA1[1]); i++) {
weeksA.push(parseInt(i))
}
}
} else {
var weeksA1 = weeksHtml.split('(');
weeksA.push(weeksA1[0]);
}
return weeksA;
}
/**
得到单科课程信息(个人课表)
*/
function getClassUser(classHtml, day, section) {
var classA = [];
var classs = classHtml.split('<br>');
if (classs.length > 1) {//防止空课程
if (classs.length <= 6) {//当课程为标准课程
var classObj = {};
classObj.name = classs[0];
classObj.position = classs[3];
classObj.teacher = classs[2];
classObj.weeks = [].concat(getWeeksUser(classs[1]));
classObj.day = day;
classObj.sections = [];
classObj.sections.push(time[(section - 1)]);
classObj.sections.push(time[(section)]);
classA.push(classObj);
} else {//当课程为双课程
//第一节课
var classObj = {};
classObj.name = classs[0];
classObj.position = classs[3];
classObj.teacher = classs[2];
classObj.weeks = [].concat(getWeeksUser(classs[1]));
classObj.day = day;
classObj.sections = [];
classObj.sections.push(time[(section - 1)]);
classA.push(classObj);
//第二节课
if(classs[5].indexOf('调')!=-1){
var classObj1 = {};
classObj1.name = classs[7];
classObj1.position = classs[10];
classObj1.teacher = classs[9];
classObj1.weeks = [].concat(getWeeksUser(classs[8]));
classObj1.day = day;
classObj1.sections = [];
classObj1.sections.push(time[(section)]);
classA.push(classObj1);
}else{
var classObj1 = {};
classObj1.name = classs[5];
classObj1.position = classs[8];
classObj1.teacher = classs[7];
classObj1.weeks = [].concat(getWeeksUser(classs[6]));
classObj1.day = day;
classObj1.sections = [];
classObj1.sections.push(time[(section)]);
classA.push(classObj1);
}
}
}
return classA;
}
/**
周次解析(个人课表)
*/
function getWeeksUser(weeksHtml) {
var weeksStr = weeksHtml;
var weeksA = [];
if (weeksStr.indexOf('-') != -1) {
var weeksA1 = weeksHtml.split('-');
var start = 0;
var end = 0;
if (weeksA1[0][weeksA1[0].length - 2] != '第') {
start = parseInt(weeksA1[0][weeksA1[0].length - 2] + weeksA1[0][weeksA1[0].length - 1])
} else {
start = parseInt(weeksA1[0][weeksA1[0].length - 1])
}
if (weeksA1[1][1] != '周') {
end = parseInt(weeksA1[1][0] + weeksA1[1][1])
} else {
end = parseInt(weeksA1[1][0])
}
if (weeksStr.indexOf('单') != -1) {
for (var i = start; i <= end; i = i + 2) {
weeksA.push(i);
}
} else if (weeksStr.indexOf('双') != -1) {
for (var i = start; i <= end; i = i + 2) {
weeksA.push(i);
}
} else {
for (var i = start; i <= end; i++) {
weeksA.push(parseInt(i))
}
}
}
return weeksA;
}
对一些奇怪的课表进行一下适配,都是一些字符串处理的方法,没有什么大的难度,几个方法基本上结构一致,只不过解析部分有稍许的不同,现在我们把写好的这些方法用到课表解析部分,最终代码如下所示:
function scheduleHtmlParser(html) {
var $ = cheerio.load(html, { decodeEntities: false });
if ($("#Table6").length > 0) {//班级课表查询界面适配
$("#Table6 tr").each(
function (i) {
if (i > 1) {
$(this).children('td').each(function (j) {
if ((i - 1) == 3 || (i - 1) == 7) {
if (j > 0) {
var classA = [].concat(getClass($(this).html(), j, (i - 1)));
if (classA.length === 1) {
jsonArray.push(classA[0]);
} else if (classA.length === 2) {
jsonArray.push(classA[0]);
jsonArray.push(classA[1]);
}
// console.log("第"+(i-1)+"节课,周"+(j)+"课程名称:"+$(this).html());
}
} else if ((i - 1) == 1 || (i - 1) == 5 || (i - 1) == 9) {
if ((j - 1) > 0) {
var classA = [].concat(getClass($(this).html(), (j - 1), (i - 1)));
if (classA.length === 1) {
jsonArray.push(classA[0]);
} else if (classA.length === 2) {
jsonArray.push(classA[0]);
jsonArray.push(classA[1]);
}
// console.log("第"+(i-1)+"节课,周"+(j-1)+"课程名称:"+$(this).html());
}
}
})
}
}
)
}
else {//个人课表查询界面适配
$("#Table1 tr").each(
function (i) {
if (i > 1) {
$(this).children('td').each(function (j) {
if ((i - 1) == 3 || (i - 1) == 7) {
if (j > 0) {
var classA = [].concat(getClassUser($(this).html(), j, (i - 1)));
if (classA.length === 1) {
jsonArray.push(classA[0]);
} else if (classA.length === 2) {
jsonArray.push(classA[0]);
jsonArray.push(classA[1]);
}
// console.log("第"+(i-1)+"节课,周"+(j)+"课程名称:"+$(this).html());
}
} else if ((i - 1) == 1 || (i - 1) == 5 || (i - 1) == 9) {
if ((j - 1) > 0) {
var classA = [].concat(getClassUser($(this).html(), (j - 1), (i - 1)));
if (classA.length === 1) {
jsonArray.push(classA[0]);
} else if (classA.length === 2) {
jsonArray.push(classA[0]);
jsonArray.push(classA[1]);
}
// console.log("第"+(i-1)+"节课,周"+(j-1)+"课程名称:"+$(this).html());
}
}
})
}
}
)
}
var jsonArray1 = JSON.stringify(jsonArray);
var time1 = JSON.stringify(time);
var conss = new Object();
conss.courseInfos = JSON.parse(jsonArray1);
conss.sectionTimes = JSON.parse(time1);
var json2 = JSON.stringify(conss);
console.info(JSON.parse(json2));
return JSON.parse(json2);
}
代码完成后,我们再对不同的课表进行测试,最后测试成功,上传代码等待小爱课程表官方审核即可,
小爱课程表审核时间应该就1天,如果出现好几天没有审核的情况应该是代码出现了问题。