今天发现一个实用的小工具-小爱课程表适配工具,可以在我的教务系统中匹配数据,导入到小爱课程表中,还可以帮助同学导入,一次适配全校适用,只需要浏览器环境就行了,很方便
可以先看一下它的官方文档
https://ldtu0m3md0.feishu.cn/docs/doccnhZPl8KnswEthRXUz8ivnhb
好了我们来分析一下他是怎么导入的
基本的流程是通过解析页面的html获取课程数据,整理成标准的数据结构,然后在手机端保存课程
接下来我们举个例子
你看这就是我的教务系统的页面,里边很直观的可以看到我的课程
接下来我们就要获取这个页面的html
右侧的provider函数,就是用来获取html的函数,默认会传入document对象,
document就是整个页面的对象,它包含了页面的所有信息,包括页面的html
其实我们直接就能用document.html取到页面的html,但是呢,有些教务系统他喜欢内嵌iframe或者frame,所以我们的provider函数中就去递归了一下,去取到页面html,和页面中嵌套的iframe中的惠html,他可能嵌套了很多层,但是我们递归一下就全部取出来了
工具中给出了默认的provider函数,几乎能搞定所有的教务系统,点击右键运行,即可弹出html的页面,你可以在弹出的页面中随便查一下自己的课程,如果页面中包含了你的课程信息,那恭喜你他是完美适用的无需更改。如果弹出的html中不包含你的课程信息,那你就需要看看该怎么取更合适了。可以自己改写这个函数,调试一下。
我们拿到了页面的html,接下来我们解析这个html片段,从中提取课程信息,整理成符合要求的数据结构。
刚刚得到的html是一大长串字符串。我们可以用正则来匹配出对应的课程信息。当然这个正则就很复杂了(如果你是正则高手,当我没说...)。所以工具内提供了cheerio这个库,来帮助解析html
工具中内置了cheerio(页面在工具中已经被cheerio加载过了,直接是用$这个函数即可)
使用起来很简单的,参考https://juejin.im/post/5ea131f76fb9a03c8122d6b9
cheerio这个js模块就是解析xml结构的数据,然后直接可以通过id或者class来获取对应的xml片段
举个例子
通过观察我们发现 这个 id=kbgrid_table_0的div盒子,包含了所有的课程信息。那我们就取它,
$('#kbgrid_table_0')
这样,你可以在console中运行这个函数,即可看到它的结果
或者这样,你可以取到所有的课程信息
$('#kbgrid_table_0').text()
但是这些课程都纠缠到一起了,不好分隔开
我们继续观察
可以发现这里的课程全都在tr td 中
且每一个td中的课程都包含一个课程的所有信息,
每一个td中的span标签都包含了这个课程的每一个属性,比如课程名称、上课地点、老师等
所以我们先取这个 id=kbgrid_table_0的div下的所有td,然后循环它,取每个td下的所有span,然后判断 每个span的属性,比如这里的class=title即课程名称的span,title=‘上课地点’即上课地点的span,这样我们就会把所有的课程信息取出来。
这里有一个难点,上课周数、节数还是掺杂在一起的,它不像老师、上课地点这样直接取就行了,所以我们要对它特殊处理一下
大多数教务系统是这样的
这样的
你可以用简单的正则来取出开始周,结束周,也可以用js中的split来分割,我正则一般,所以选择split这种方式,然后来一个for循环把符合要求的周次放进一个数组,这里请注意单双周要特殊处理一下
举例子:
1-3,5-7(周)[01-02节]
我观察到“(周)”这个字符可以分割开周数和节数,所以我
let result=[] //先声明一个数组保存结果
let str='1-3,5-7(周)[01-02节]'
let weeks=str.split('(周)')[0] //这样就取到了周,结果为1-3,5-7
let subWeek=weeks.split(',') //这样就得到了[1-3,5-7],接下来我们循环它
for(let i=0;i
let week=subWeek[i] //这里取到了 1-3,我们继续给他分割
let begin=week.split('-')[0] //我们取到了开始周1
let end=week.split('-')[1] //我们取到了结束周3
for(let j=begin;j
result.push(j) // 将符合要求的结果push进result数组
}
}
这样我们就取得了这节课的所有周,保存在了result中(当然你也可以直接用正则匹配开始周和结束周然后循环)
节数的处理也类似
这样我们就取到了所有课程的所有属性(通过两层for循环和多个if判断)
然后我们再把数据结构整理成官方文档中要的格式,就完工啦