子墨的博客

总得让实力配上野心


  • 首页

  • 标签71

  • 分类16

  • 归档29

  • 关于

  • 搜索

一种导入小爱课程表的非一般方法

置顶 发表于 2020-11-02 分类于 爬虫 , 抓包 阅读次数:
本文字数: 7.4k 阅读时长 ≈ 7 分钟

本文原理性说明略多,如不想看,那么下面的一键直达,应该适合你

点此一键直达

或者使用另一个开源项目

前言

《小爱课程表》是小米最新推出的课程表应用。

所有使用MIUI12的小米手机都自带,它具有课程提醒和上课静音的功能,并且支持负一屏展示、日历订阅等非常实用的功能。

当然,其他手机也能用,小爱课程表应用目前已经上架了多个应用商店,包括iOS 和安卓商店,所以,只需要去应用商店搜索「小爱课程表」下载即可食用,它相比其他课程表产品的优势在于:更新及时,界面简洁无广告,设置课程便捷,可添加桌面小部件(所以负一屏展示这个功能,可能就MIUI12支持了吧,安利一下)。

下面放一些效果图:

负一屏

上课静音提醒

另外,值得一提的是,小爱课程表推出了和小爱同学一起打造最好用的课程表的内测功能,号称:只需一点JS基础,几十行代码,便可参与课程表项目,体会代码落地产品的乐趣,用你的高超技艺造福同校同学!,如果你有适配的想法,请戳官方文档

如果你想适配,但苦于没有参考,想找个参考的话,可以看一下我的开源项目成都信息工程大学 小爱课程表适配

原理

下面本文的重点来了,先简单介绍一下小爱课程表这个适配功能原理:小米的工程师们提供了一个webview,让开发者可以在页面上加载出你的课程表,然后通过你使用官方提供的chrome浏览器插件开发好的scheduleHtmlProvider.js和scheduleHtmlParser.js解析出符合小爱预定义好的规范的json数据,点击一键导入之后,通过https请求提交到小米的服务器,然后小爱课程表根据这个json数据进行课程表的渲染,单就原理而言,并没有什么太大的问题,但是坑就坑在Android的webview,这个无法渲染出js动态生成的课程表(目前已知金智和树维的教务系统,无法渲染出来,登陆之后会白屏,就像下面这张图一样)

Android端webview无法渲染某些动态js,所以白屏

博主也是在适配完了我们学校的小爱课程表之后,才发现这个问题的,这适配完了,用不了的情况,就很不舒服,于是尝试寻找解决办法

破局

在理解了小爱课程表适配功能的原理之后,发现,我们缺少的其实就只有提交到小米的服务器这一步,所以从另一个角度来看,我们完全可以自己提交课程数据给小米的服务器,于是说干就干,抓个包来看看小爱课程表提交到小米的服务器的数据是什么样子的,在这里我选用的抓包工具是小黄鸟

配置小黄鸟

  1. 下载并安装小黄鸟,GitHub传送门

  2. 打开小黄鸟,安装证书等等

  3. 设置小黄鸟的目标应用为小爱同学

  4. 开始抓包

  5. 打开小爱同学,添加一条测试课程看看

  6. 发现提交课程的报文如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    POST /course/courseInfo h2
    Host: i.ai.mi.com
    content-length: 272
    access-control-allow-origin: true
    user-agent: Mozilla/5.0 (Linux; Android 10; MI CC 9 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36
    content-type: application/json
    accept: */*
    origin: https://i.ai.mi.com
    x-requested-with: com.miui.voiceassist
    sec-fetch-site: same-origin
    sec-fetch-mode: cors
    sec-fetch-dest: empty
    referer: https://i.ai.mi.com/h5/precache/ai-schedule/
    accept-encoding: gzip, deflate
    accept-language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7

    {"weeks":"1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20","name":"测试","position":"","teacher":"","sections":"2","day":1,"style":"{\"color\":\"#00A6F2\",\"background\":\"#E5F4FF\"}","csId":2371853867,"userId":123436229,"deviceId":"a88374c981cf771f8360dabcde4c3574"}

分析报文

接口地址:https://i.ai.mi.com/course/courseInfo
接口传递的json及其字段含义:

1
2
3
4
5
6
7
8
9
10
11
12
{
"weeks": "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20",// 课程上课周数
"name": "测试",// 课程名称
"position": "",// 课程上课地点
"teacher": "",// 课程上课老师
"sections": "2",// 课程是第几节课
"day": 1,// 课程是周几上课
"style": "{\"color\":\"#00A6F2\",\"background\":\"#E5F4FF\"}",// 字体背景颜色设置
"csId": 2371853867,// 课程id,可以不提交
"userId": 123436229,// 用户id,可以在vConsole的LocalStorage中获取到,此处我的id已打码,vConsole,连续点击荣誉coder下方空白区域调出
"deviceId": "a88374c981cf771f8360dabcde4c3574"// 设备id,可以在vConsole的LocalStorage中获取到,此处我的id已打码
}

比较

将抓取到的接口和我们按照官方文档渲染出来的json格式比较一下:
可以发现,sections和weeks字段有些许的不同,另外,缺少了style,userId,deviceId字段,基于此,我们可以稍微修改一下js解析出来的格式,并且加入缺少的字段,然后模拟请求提交给小米的服务器即可
比较

修改json格式:

  1. “weeks”:由数组改成字符串,逗号分割
  2. “sections”:由数组改为字符串,逗号分割
  3. 增加userId,deviceId字段,值为vConsole的LocalStorage中的相关值
  4. 增加style字段,可以给默认值为"{\"color\":\"#00A6F2\",\"background\":\"#E5F4FF\"}",或者自定义,建议默认值,不会影响负一屏的效果,但缺点就是不够个性化

模拟请求

原理写了一大堆,相信大家应该都懂了,所以这里只给出一个写好的python脚本,依赖python3,requests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# -*- coding:utf-8 -*-
import requests
import json

courseInfos = json.loads(
'{"courseInfos":[{"day":1,"sections":"1,2","name":"操作系统结构","teacher":"徐虹","weeks":"1,2,3,4,5,6,7,8","position":"H4303"},{"day":2,"sections":"1,2","name":"信息系统安全","teacher":"张永清","weeks":"9,10,11,12","position":"H4501"},{"day":2,"sections":"1,2","name":"数字图像处理及应用","teacher":"胡金蓉","weeks":"5,6,7,8","position":"H4501"},{"day":3,"sections":"1,2","name":"高等工程数学","teacher":"任红萍","weeks":"1,2,3,4,5,6,7,8,9,10","position":"H4501"},{"day":4,"sections":"1,2","name":"英语一","teacher":"李翠兰","weeks":"1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16","position":"H2403"},{"day":5,"sections":"1,2","name":"云计算","teacher":"王婷","weeks":"1,2,3,4","position":"H4303"},{"day":2,"sections":"3,4","name":"英语一","teacher":"李翠兰","weeks":"1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16","position":"H4301"},{"day":3,"sections":"3,4","name":"云计算","teacher":"王婷","weeks":"1,2,3,4","position":"H4303"},{"day":3,"sections":"3,4","name":"数据挖掘","teacher":"马健兵","weeks":"9,10,11,12","position":"H4501"},{"day":4,"sections":"3,4","name":"信息系统安全","teacher":"张永清","weeks":"9,10,11,12","position":"H1603"},{"day":4,"sections":"3,4","name":"物联网技术","teacher":"沈艳","weeks":"5,6,7,8","position":"H4601"},{"day":1,"sections":"5,6","name":"高等工程数学","teacher":"任红萍","weeks":"1,2,3,4,5,6,7,8,9,10","position":"H4305"},{"day":2,"sections":"5,6","name":"物联网技术","teacher":"沈艳","weeks":"5,6,7,8","position":"H4501"},{"day":2,"sections":"5,6","name":"现代数据库技术","teacher":"邹茂扬","weeks":"1,2,3,4","position":"H4501"},{"day":2,"sections":"5,6","name":"虚拟现实","teacher":"魏敏","weeks":"9,10,11,12","position":"H4501"},{"day":3,"sections":"5,6","name":"操作系统结构","teacher":"徐虹","weeks":"1,2,3,4,5,6,7,8","position":"H4304"},{"day":3,"sections":"5,6","name":"自然辩证法概论","teacher":"黄澜","weeks":"9,10,11,12,13,14,15,16,17","position":"H1301"},{"day":4,"sections":"5,6","name":"现代数据库技术","teacher":"邹茂扬","weeks":"1,2,3,4","position":"H4303"},{"day":4,"sections":"5,6","name":"数字图像处理及应用","teacher":"胡金蓉","weeks":"5,6,7,8","position":"H4303"},{"day":4,"sections":"5,6","name":"虚拟现实","teacher":"魏敏","weeks":"9,10,11,12","position":"H4305"},{"day":1,"sections":"7,8","name":"数据挖掘","teacher":"马健兵","weeks":"9,10,11,12","position":"H4303"}]}')
exclude = ['虚拟现实', '数字图像处理及应用', '嵌入式系统', '云计算', '物联网技术']
userId = 123436229
deviceId = 'a88374c981cf771f8360dabcde4c3574'
# i = 2371853867
for course in courseInfos['courseInfos']:
if course['name'] in exclude:
continue
# course['csId'] = i
course['userId'] = userId
course['deviceId'] = deviceId
course['style'] = '{\"color\":\"#00A6F2\",\"background\":\"#E5F4FF\"}'
data = json.dumps(course, ensure_ascii=False)
headers = {
'Host': 'i.ai.mi.com',
'content-length': str(len(data)),
'access-control-allow-origin': 'true',
'user-agent': 'Mozilla/5.0 (Linux; Android 10; MI CC 9 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36',
'content-type': 'application/json',
'accept': '*/*',
'origin': 'https://i.ai.mi.com',
'x-requested-with': 'com.miui.voiceassist',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://i.ai.mi.com/h5/precache/ai-schedule/',
'accept-encoding': 'gzip, deflate',
'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
}

res = requests.post(url='https://i.ai.mi.com/course/courseInfo', headers=headers, data=data.encode())
print(res.text)
print(data)
# i += 1

使用方式

可以直接使用我的这个开源项目,前提是你们学校的课程表已经适配了,不然你需要先适配

成信大学子

  1. clone 适配小爱课程表的项目到本地
  2. 登陆教务管理系统,保存课表html
  3. 打开小爱课程表,在vConsole的LocalStorage中拿到userId和deviceId;vConsole,可以通过连续点击荣誉coder下方空白区域调出
  4. 拿到课表的table的HTML源代码放到course_table_demo.html的body中
  5. 双击course_table_demo.html,用浏览器查看,并在console中将打印出来的课表json复制出来
  6. 修改上面的python脚本的相关配置为自己的,然后运行python脚本
  7. enjoy it

其他学校学子

  1. 适配小爱课程表
  2. 接下来就和上面一样了

致谢

部分思路来自于:

  1. 导出课表到小爱课表的一种方法,支持单双周/教师教室/背景色
  2. 将超级课程表的课程一键导入至小爱课程表
相关文章
  • jupyter初体验
  • 基于油猴的力扣题目转换工具 html转markdown 便于写题解
觉得不错,打赏一下
子墨 微信支付

微信支付

子墨 支付宝

支付宝

  • 本文作者: 子墨
  • 本文链接: https://blog.zimo.wiki/posts/bf2ec5ab/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
python JavaScript 小爱课程表 抓包 HttpCanary
实战fiddler劫持高德地图api伪装位置
基于油猴的力扣题目转换工具 html转markdown 便于写题解
  • 文章目录
  • 站点概览
子墨

子墨

子墨的博客
29 日志
16 分类
71 标签
RSS
GitHub E-Mail CSDN QQ Gitee
友情链接
  • 高正杰的博客

Tag Cloud

  • 8076
  • HttpCanary1
  • JavaScript2
  • Jupyter Notebook1
  • c++1
  • centos1
  • cuda1
  • c语言6
  • deepin1
  • dns2tcp1
  • fiddler1
  • hexo2
  • html1
  • i至诚1
  • jar1
  • java3
  • jetbrains1
  • linux3
  • linux server1
  • markdown1
  • nginx1
  • nodejs1
  • python2
  • python31
  • pytorch1
  • tesseract-ocr1
  • ubantu1
  • virtualenvwrapper-win1
  • war1
  • windows2
  • windows server1
  • 个人博客2
  • 代理1
  • 代码托管1
  • 代码雨1
  • 伪装位置1
  • 使用指南1
  • 刷recovery1
  • 力扣1
  • 劫持1
  • 双系统1
  • 小爱课程表1
  • 小米61
  • 常识1
  • 快捷键冲突1
  • 抓包1
  • 折腾1
  • 挖矿木马1
  • 服务器1
  • 机器学习2
  • 极客1
  • 树梅派4001
  • 油猴脚本1
  • 爬虫1
  • 环境搭建1
  • 直播服务器1
  • 科普1
  • 程序综合设计6
  • 算法1
  • 终端1
  • 编译1
  • 考研7
  • 自动打卡1
  • 蓝桥杯1
  • 解锁bl1
  • 运维1
  • 部署1
  • 钉子户1
  • 题解1
  • 黑客帝国1
  • 黑苹果1
  1. 1. 本文原理性说明略多,如不想看,那么下面的一键直达,应该适合你
  2. 2. 前言
  3. 3. 原理
  4. 4. 破局
    1. 4.1. 配置小黄鸟
    2. 4.2. 分析报文
    3. 4.3. 比较
    4. 4.4. 模拟请求
  5. 5. 使用方式
    1. 5.1. 成信大学子
    2. 5.2. 其他学校学子
  6. 6. 致谢
蜀ICP备18029083号 © 2019 – 2022 子墨 | 站点总字数: 167k | 站点阅读时长 ≈ 2:32
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Pisces v7.3.0
载入网站运行时间中...
|
0%