小爱同学课程表——河南理工大学教务系统适配

<小爱同学课程表>

-————河南理工大学教务系统(树维教务系统)适配

小爱同学课程表的教务系统导入是在小爱同学3.0推出的,也就是去年的9月份左右。给大学生的生活提供了很大的遍历,但是就搜索了一下我们学校的教务处,并没有适配,直到今年假期,绝对要尝试去适配。开始了简单的js学习,加之大一的时候就开始学习python爬虫,学习js就容易很多(并且在学习过程中发现js的语法有很多不是和c一样就是和python一样),而且这个适配也算是对课程表的爬取。下面就简单分享一下整个编写的流程。开头先介绍一下小爱同学的课程表,非常的方便,他不仅局限于MIUI系统,其他系统也可以在应用商店下载小爱同学或者单独下载小爱课程表。
本次的代码已开放到github,大家可以下载:
奥利给小爱同学3.0

废话少说,直接进入主题,本次将通过以下几个步骤去论述:

目录:

0:项目设计流程及代码参考
1:provide函数编写以及其他案例
2:paser函数编写以及调试
3:上传以及E2E测试
0_0:相关文档及代码参考:

官方文档飞机票:https://ldtu0m3md0.feishu.cn/docs/doccnhZPl8KnswEthRXUz8ivnhb
github代码链接:https://github.com/https-github-com-hpu-ylx/AIschedu-HPU_schedule.git
本文参考博客: 二氢茉莉酮酸甲酯

0_1:设计流程

整体流程

1_0:先运行官方的provide函数
provider函数的作用就是以html文档的形式返回网页内容,供parser函数调用
function scheduleHtmlProvider(iframeContent = "", frameContent = "", dom = document) {
    //除函数名外都可编辑
    //以下为示例,您可以完全重写或在此基础上更改
                                
const ifrs = dom.getElementsByTagName("iframe");
const frs = dom.getElementsByTagName("frame");

if (ifrs.length) {
    for (let i = 0; i < ifrs.length; i++) {
        const dom = ifrs[i].contentWindow.document;
        iframeContent += scheduleHtmlProvider(iframeContent, frameContent, dom);
        }
} 
if (frs.length) {
    for (let i = 0; i < frs.length; i++) {
        const dom = frs[i].contentDocument.body.parentElement;
        frameContent += scheduleHtmlProvider(iframeContent, frameContent, dom);
        }
} 
if(!ifrs.length && !frs.length){
    return dom.querySelector('body').outerHTML
}
return dom.getElementsByTagName('html')[0].innerHTML + iframeContent+frameContent  
}
1_1:HTTP请求

因为HPU的教务系统可以用官方的DOM方法,所以重点将如何用http方式获取,当然这也是我最后无意中尝试才发现的,在这里先说一下我之前的provider函数是怎么写的:
刚开始因为对js的爬取不了解,所以只能参考其他人的代码他是用的http方式获取的:

1 function scheduleHtmlProvider(iframeContent = "", frameContent = "", dom = document) {
2   let http = new XMLHttpRequest()
3   http.open('GET', '/jsxsd/xskb/xskb_list.do?Ves632DSdyV=NEW_XSD_PYGL', false)
4   http.send()
5   return http.responseText
6 }

通过http方式获取网页内容并返回,因为python的爬虫获取网页是用的request函数,并且伪装headers,如今面对的是js,有点无从下手的感觉,只能照猫画虎,把open()函数中的url替换成HPU的课表的url:
在这里插入图片描述
这个是课表页面的url

function scheduleHtmlProvider(iframeContent = "", frameContent = "", dom = document)
{//函数名不要动
	    let http = new XMLHttpRequest()
	    http.open('GET',"http://218.196.248.100/eams/homeExt.action",false)
	    http.send()
    return http.responseText
}

这就是照猫画虎的代码,我们直接在控制台运行:并添加控制台打印语句(这里推荐使用console.info以便后期E2E测试):
控制台输入代码:
在这里插入图片描述

1_2:如何判断请求方式

这时也可以看到控制台打印出了我们所要的东西,及该也面的源码。
注意!注意!注意!重要的事情说三遍:我们如何判断网页是否是允许GET方式获取的?那么如果允许它的url到底怎么写?经过我的咨询标准操作应该是这样的:
1.按住ctrl+shift+i或f12调出控制窗口
2.在第一个栏里面找到第四个选项卡Network
3.然后clear历史记录
4.刷新页面返回到登录页面
5.找到第一个出现的请求文件
6.打开起请求头Headers
在这里插入图片描述

获取方式:GET
返回码:200(返回200意味请求头请求成功)
例如最常见的的请求码404代表的意思就是浏览器发出请求后,未在服务器找到相应的资源,及404 not found

根据这个我们还可以看出我们所写的url后面应该为loginExt.action,open()函数中的请求方式为GET
至此,我们就把网页的html爬取下来了,为了验证返回结果我们进入parser函数。

2_0:定位课表所在HTML标签

开发者调试窗口然后点开左上角的箭头定位课程表内容
在这里插入图片描述
python中对html标签解析是对json格式操作的:
在这里插入图片描述

而js则需要用到jQuery选择器,简单来说就是它可以通过id,class等来获取html标签内容,具体内容可以查看上文中提到的文档,这里咱们只需要用到一点
首先介绍几个简单的html标签:<table>表格</table>,<th>表头</th>,<td>表属性,内容</td>
在这里插入图片描述
从图中可以看出课表的内容在td子标签中,该子标签被包含在table这个父标签中,所以我们可以写出以下jQuery代码:let $raw = $("#manualArrangeCourseTable .infoTitle");,前面为id,后面为class。parser函数

function scheduleHtmlParser(html)
{
    let $raw = $("#manualArrangeCourseTable .infoTitle");
    console.info($raw);
}  

在这里插入图片描述
运行后返回object数组(并且数组15个元素,正好对应15节课),则provider函数返回参数没得问题,若返回的为空数组则在控制台测试其provider函数返回结果为什么,以及parser函数传入参数的内容.

2_1:思路

在这里插入图片描述
这是官方文档中的几个规定变量:
现在我们直接观察数组,对数组进行解析:

在这里插入图片描述
从图中可以看出课程名字,老师名字,教室,一共几周都可以看出来,而且都在title里面,我们只需要遍历数组出数组里面的title,然后用字符串切割方法去取对应的内容。这个时候还有一个大问题来了:怎么判断这节课是在星期几,以及有几小节。通过对比每个数组里面的元素不难发现,不同点在id,rowspan里面,其中rowspan代表有几节,id代表的意义我画了张表:在这里插入图片描述
TD这两个字符不变,下划线和下划线后面的字也不变,变的只是TD和_直接的数字,可以这样理解,第一位数字+1表示星期几,第二位则表示第几大节。思路清晰,开干!

2_1:将title,id,rowspan遍历出来
for(str in $raw)    //对object数组进行遍历,将id和title提取出来
    {
        date = $raw[str]
        title_text = date.attribs.title;    
        //里面包含了课程名字,教师名字,周次,教室
        //信号与系统(130122020.001) (李辉,张培玲);;;(4-15,南校区  南校区1号教学楼	1207)

        id_text = date.attribs.id;
        //用来获取星期几低级大节
        rowspan_text = date.attribs.rowspan;
        //通过来判断有几小节课
        
/*********控制台输出测试片段********/
        //方便测试调试
        
        console.info(title_text);
        console.info(id_text);
        console.info(rowspan_text);
        
/*********************************/
     }

输出结果:
在这里插入图片描述

2_2:如何提取字符串内容

需要用到的几个js函数:

indexOf()//从左开始某个元素第一次出现的位置
lastIndexoOf()//从右边开始某个元素第一次出现的位置
substring(start, end)//截取从开始到结尾位置之间的所有内容,包括start不包括结尾

substring在线练习
当然也可以用正则表达式:
正则表达式测试
正则表达式入门

2_3:课程,教师,教室,周次

通过上面的遍历,我们现在吧获取到的title字符串拿出来:

信号与系统(130122020.001) (李辉,张培玲);;;(4-15,南校区  南校区1号教学楼	1207)
name:
/*******获取课程名字*****/
        //a_1计算出第一个左括号出现的位置
        a_0 = title_text.indexOf('(');
        //直接获取出name的位置
        name = title_text.substring(0, a_0);
        console.info(name);
teacher:
/******获取教师名字******/
        a_1 = title_text.indexOf(')');
        //找出第一个)所在的位置,则老师的姓名即为a_1 + 3,因为中间有个空格
        b = title_text.indexOf(';');
        //同理,找好合适的定位点
        teacher = title_text.substring(a_1 + 3, b - 1);
        console.info(teacher);
weeks:
/******获取课程周期******/
		//前面我们把name,teacher,都提取出了,现在title整个有用的部分就剩后面了,所以我们把后面单独拉出来
        c_1 = title_text.lastIndexOf('(');//最后(出现的位置
        c_2 = title_text.lastIndexOf(')');//最后)出现的位置
        str_1 = title_text.substring(c_1 + 1, c_2);//将最后一个括号的所有内容拉出来
        //4-15,南校区  南校区1号教学楼	1207)
        c_3 = str_1.indexOf(',');//,出现的位置
        weeks = str_1.substring(0, c_3);  
        console.info(_get_week(weeks));
positions:
/******教室******/
        //V4-15,南校区  南校区1号教学楼	1207
        d_0 = str_1.indexOf(' ');
        d_1 = str_1.lastIndexOf(' ');
        position = str_1.substring(c_3 + 1);//substring如果不写end默认全部
        console.info(position);
        //南校区  南校区1号教学楼	1207
2_4:星期几,第几节

之所以把这个单独拉出来,是因为前面那几个不需要太多代码,所以没必要写函数,这几个则需要单独写函数里面,一方面是为了好看,二也是为了测试的时候好检查

day:

前面我们讲解了id这个参数每个字符代表的意义,我们先把TD和_中间的数字提取出来,并取模,通过switch来输出多种情况

function _get_day(id)//返回星期几,传入的参数为id_text
{
    let week_num;
    let num;
    if(id.substring(3, 4) == '_')
    {
        num = id.substring(2, 3);
    }
    else
    {
        num = id.substring(2, 4);
    }
    switch(parseInt(num / 10))
    {
        case 0:
            week_num = 1;
            break;
        case 1:
            week_num = 2;
            break;
        case 2:
            week_num = 3;
            break;
        case 3:
            week_num = 4;
            break;
        case 4:
            week_num = 5;
            break;
        case 5:
            week_num = 6;
            break;
        default:
            week_num = 7;
            break;
        
    }
    return week_num;
}
section:

返回第几节,且为数组

function _get_section(id, n)//传入id_text,rowspan_text代表传入的数据
{
    let section = [];
    let num;
    let i;
    //因为周一为TDx_0,其他为TDxx_0,所以先判断为周一还是其他
    if(id.substring(3, 4) == '_')//判断是否为周一
    {
        num = id.substring(2, 3);   //如果为周一,则取第二个字符
    }
    else
    {
        num = id.substring(3, 4);   //否则取第三个字符
    }
    num = Number(num);
    n = Number(n);
    i = num;
    switch(num)
    {
        case 0:
            for(num; num < i + n; num++)//
            {
                section.push({"section":num + 1});
            }
            break;
        case 2:
            for(num; num < i + n; num++)//
            {
                section.push({"section":num + 1});
            }
            break;
        case 4:
            for(num; num < i + n; num++)//
            {
                section.push({"section":num + 1});
            }
            break;
        case 6:
            for(num; num < i + n; num++)//
            {
                section.push({"section":num + 1});
            }
            break;
        default:
            for(num; num < i + n; num++)//
            {
                section.push({"section":num + 1});
            }
            break;
    }
    return section;

}
weeks:

前面获取到了第几周,但是格式是4-7,这种的,根据官方文档需要改成数组:
在这里插入图片描述
其实这个思路应该很早就有:哈哈,就是招募问卷里面的题
在这里插入图片描述
这里引用的还是上文中提到的博客中的

//将每节课的周次按照数组的形式返回
function _get_week(data) 
{
	//weeks data will be inputed as '4,7-18', to handle ,we will split them by ',' and operate seperately.
    let result = [];
    let raw = data.split(' ');
    let i;
    for (i in raw) 
    {

        if (raw[i].indexOf('-') == -1) 
        {
        	//create array
            result.push(parseInt(raw[i]));
        } 
        else {
            let begin = raw[i].split('-')[0];
            let end = raw[i].split('-')[1];
            for (let i = parseInt(begin); i <= parseInt(end); i++) 
            {
                result.push(i);
            }
        }
    }
    //sort the array,
    return result.sort(function (a, b) 
    {
        return a - b
    });
}

最后直接时间直接套用官方的改成HPU作息时间表,这个不用担心夏季和冬季。
最后,测试结果:AII run successfully
在这里插入图片描述

3_0:上传,E2E测试

上述完成后就大功告成了,上传后,在手机端打开vsconsole测试(只有MIUI系统的手机才会有开发者选项vConsole)
在这里插入图片描述

可悲的是,小爱同学登不了我们学校的教务处,一直点登录没反应,但是其他手机可以登陆进去(玄学)
不过官方给出了说法:第3点,刚好我们是树伟维的系统在这里插入图片描述
在这里插入图片描述
所以,最后的提交,内测,过程我就不演示了,大家可以看我开头提到的博客,里面有提到。

最后也非常感谢二氢茉莉酮酸甲酯的指导与帮助,毕竟我也不是计算机专业的,js也是学了没几天,所以欢迎大家来讨论,如果有有问题的小伙伴可以联系:

email:15513924345@163.com
QQ:1639446186

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值