华电课程系统适配小米小爱课程表记录
华电是真没多少名气, 本来想要用一下小爱同学的课程表教务系统导入功能, 结果只搜到俩项目, 一个是保定的一个还打不开( 估计是用的学校内网url ). 闲着也是闲着, 不如自己适配一下学校的教务系统.
本文纯属记录, 并非是为讲述代码原理( 咱也是现学现卖
整体思路
小爱同学课程表适配仅需要完善三个方法, 分别是网页抓取方法 scheduleHtmlProvider
, 数据处理方法scheduleHtmlParser
, 以及开课时间方法scheduleTimer
, 第三个方法其实只需要按照注释填写好返回值即可.
使用工具
当前小爱课程表适配工具 AI Schedule
是 Ver.3.2.0214
版本, 界面简洁舒适, 挺好看的就是非常难用, 所以咱是用的 0.1.4
版本编写好代码之后, 再直接扔到新版本上提交, 因此该文记录的是旧版本的代码编写过程
旧版本 AISchedule DevTools 0.1.4
新版本 AISchedule DevTools 0.3.3
两个都是浏览器插件, 下载解压后在Chrome中扩展程序中打开开发者模式, 加载已解压的扩展程序, 找到相应的解压后的文件夹导入扩展程序即可启用
插件使用过程
- 下载AISchdule DevTools压缩包, 解压到本地.
- 下载Chrome, 打开链接 chrome://extensions/ , 打开开发者模式, 导入AISchedule DevTools文件夹.
- 在Chrome打开一个新的Tab, 打开, 登陆自己的教务系统, 进入课程页面( 比如下图展示课程表) .
- 在网页内右键, 选 [检查] , 打开Chrome开发者工具, 会有新增的AISchedule标签, 进入后请跟随新手引导, 创建 [适配项目] . 注意: 学校url请填写官方url, 不要填写ip或者代理!
- 当点击provider/parser函数的代码区时, 会跳转到sources中, 在此你可以编辑
scheduleHtmlProvider
方法,scheduleHtmlParser
方法, 并打断点debug.
- 可以参考注释与示例函数, 编写两个适配函数. 按ctrl+s/cmd+s保存, 然后在网页中右键, 选 [AISchedule DevTools 运行] , Console中会打印出运行结果, 两个函数的输出会分别在新窗口中显示, 以便边参考边修改函数.
- 经过调试, 如果在console中看到 [All run successfully] , 然后就可以复制到新版本插件, 创建项目, 右上角上传, 进行E2E自测 (端到端自测) .
- 在手机端打开课程表的教务导入功能, 搜索学校, 选择自己提交的适配, 即可亲自体验, 验证可用性. (此时版本为开发版)
如果觉得没问题, 点击反馈按钮 [完美] (此时版本将自动变为预览版)
然后在新版本插件中提交审核即可, 审核通过后项目将变为正式版
代码
scheduleHtmlProvider
此方法只要获取到课程表, 利用浏览器的元素检查可以很快定位到课程表 id
确定课程表 id 为 kbgrid_table_0
后在 scheduleHtmlProvider
返回即可, 代码如下
function scheduleHtmlProvider(iframeContent = "", frameContent = "", dom = document) {
return dom.querySelector('#kbgrid_table_0').outerHTML
}
执行该方法后结果会弹出图中所示窗口
scheduleHtmlParser
该方法解析上一个方法返回的课程表获得相应的数据, 代码及注释如下
function scheduleHtmlParser(html) {
let result = []
let data = $("td")
// 按照字符串 'td' 分离数据
console.log(data)
for(let i = 0 ; i < data.length ; i++){
let id = data[i].attribs.id
// 获取当前结点的 'id' 值, 在华电教务系统中, 只有课程数据才会提供 id 值, 该值为 dd-nn 格式, dd 为课程在星期几, nn 为课程在第几节
if(id == undefined)
continue
if(data[i].children.length == 0)
continue
// 如果不是课程数据, 则略过; 如果没有课程数据, 则略过
let dayData = id.split('-')[0]
let sectionData = (Number(id.split('-')[1]) + 1 ) / 2
// 此处解析 id 值为星期与节数
for(let v = 0 ; v <data[i].children.length ; v++){
let test = $(data[i].children[v]).find('span')
// 这里是在课程数据中找到相应的数据结点, 因为 jQuery 中记录的数据较多, 观察网页源代码可以发现所有课程数据前都会有 span 属性的定义, 因此使用 'span' 去过滤数据
let nameData = test[0].children[0].children[0].data
let weekData
let weeksData = []
let positionData
for(let u = 1 ; u < test.length ; u++){
if(test[u].attribs.title == '节/周'){
weekData = test[u].next.children[0].data.replace(/\(.*?\)/g,'').replace('周','')
// 此处使用正则表达式去除数据中的垃圾部分, 此处是去除的括号及其内容和 '周' 这个汉字
let start = Number(weekData.split('-')[0])
let end = Number(weekData.split('-')[1])
for(;start <= end;start++){
weeksData.push(start)
}
// 此处放置上课的周数, 1-4 周就要写成整型数数组 [1, 2, 3, 4]
}
else if(test[u].attribs.title == '上课地点'){
positionData = test[u].next.children[0].data
}
}
let re = {
"name":nameData,
"position":positionData,
"teacher":'',
"weeks":weeksData,
"day":Number(dayData),
"sections":[{"section":sectionData}]
// 这里有个坑: 旧版 sections 是个 json 数组, 新版是个整形数数组
}
result.push(re)
}
}
let finalResult = {"courseInfos" : result}
console.log(finalResult)
return finalResult
// 此处返回 finalResult 是因为这是旧版本的规范, 新版本返回 result 即可
}
bug处理
-
Unchecked runtime.lastError: The message port closed before a response was received.
这个错误麻烦了我半天, 在网上查询结果都是在指责 Chrome 或者 Chrome插件, 最后发现原来是我数据返回的格式不对, 应该是数组的我用的 json , 应该是 json 的我用了数组 -
console.log()
这应该是我 debug 时最常用的代码, 遇到未知错误就打印一下, 不知道套几层.children[0].
就打印一下, 可谓是摸着打印结果写代码