超星学习通章节文件下载
出于各种原因, 上传到学习通 "章节" 里的文件并不总是具备下载按钮.

背景

在大学的学习生活中, 经常需要使用到学习通.

有些老师会将课程 PPT 上传到学习通的 “章节” 中. 但是, 出于各种原因 (主观上不情愿或者客观上不会操作), 并不是所有老师都会开启这些文件的下载功能. (注意, “章节” 有时候又称 “任务点”, 区别于课程的 “资料” 板块).

而作为学生的我们, 出于各种原因, 有时候又需要下载这些文件来查看 (学习通网页上对文件的预览并不好用), 比如打印出来, 或者存储在个人设备上便于批注和查阅.

网上流传了很多方法, 主流的方式大多是提取出 objectId 并替换到某个 URL 中, 访问即可下载. 但是这些方法大多已经失效, 访问时提示 “403 Forbidden”.

对此, 笔者认为的 可能 的原因是权限校验失败. 用户粘贴 URL 到浏览器地址栏中访问, 便丢失了先前的对话环境, 服务器无法鉴别身份, 便拒绝提供下载功能. 而之前泄露出来可用的 URL 也许只是超星方面忘记了设定身份校验.

于是便尝试在同一个网页环境中完成链接的点击.

道理是这样, 但是笔者一直没有得以成功实现.

契机

正巧, 最近笔者的好友分享了超星云盘上的文件, 奈何页面上并没有下载按钮. 在不想麻烦朋友的情况下, 同时出于对国内一众网页开发技术的了解 (混乱代码 + 客户端渲染), 直接就点开了 “开发人员工具”, 尝试对页面进行分析.

很快, 通过顺藤摸瓜的方式:

  • 先找到网页上可能出现下载按钮的位置 / 对网页上现有的元素进行检索
  • 再搜索可疑的关键字, 比如 download 或者 file 之类的单词

便发现了网页源代码中明文内嵌的一段 JavaScript 代码.

观察这段代码, 可以发现这段代码:

  • 声明了一个包含文件属性信息的 JSON 对象, 其中一个属性就是 download, 其值为一个 URL
  • 然后将一个回调函数绑定在了页面上的 #download 元素上.

虽然页面上没有找到这个元素, 可是这个回调函数里的代码还是可以执行一下试试.

这段代码大概完成的事情就是:

  • 创建一个 <a> 元素
  • 将其 href 属性设置为上面提到的 URL
  • 再将 target 属性设置为 _self
  • 最后再模拟点击

结果就是, 执行了上述代码, 浏览器就弹出了文件下载的窗口.

有一些细节: 一是需要根据页面所使用的协议对这个 URL 的协议头进行替换, 一般需要替换成 https; 二是这个 URL 除了 objectId 还包含了 at_, ak_, ad_ 等参数 (大概是用来限制文件的下载, 这些参数动态生成, 参数必须合法才能下载文件), 如果缺失这些参数则是无法下载文件的.

毕竟笔者没有什么 WEB 开发经验, 也没有深入研究超星的技术, 所以不清楚具体为什么同样的链接, 直接访问未果, 而在控制台里这样操作就可以成功下载.

延申

在笔者为了这次的问题查阅资料的过程中, 也看到了其他资料, 但是主要是和章节文件下载相关的.

事成之后, 笔者觉得这些问题之间有一定联系, 便准备将这次经历分享出来, 帮助需要的读者.

超星学习通如何下载文件 - 知乎 这个问题下有个 回答, 提供了一种较为简单直观的下载超星学习通章节任务点中文件的方法. 回答的评论下也有用户转发了一篇 CSDN 上的博客, 同样介绍了类似的方法.

问题下的 另一个回答 给出的是类似的方式, 不过看起来就没那么直观.

这个方法大概是, 检视超星加载页面时产生的网络请求, 之后找到一个请求项 (其实就是对 https://mooc1-1.chaoxing.com/ananas/status/<objectid>?flag=normal 的访问), 其返回的信息是一个 JSON 对象.

对象中主要用到的有 downloadpdf 这两个属性值:

  • download 属性对应的 URL 如果直接访问会提示 “403 Forbidden”
  • pdf 属性对应的 URL 的目前仍能够直接访问

笔者猜测, pdf 属性值给出的 URL 对应的是源文件转换而来的 PDF 文件, 而该 API 目前仍未被超星封锁, 因此尚能访问.

而笔者发现, 使用本文 “契机” 部分介绍的方式后, 访问 download 对应的 URL 仍然是可以下载到文件的.

方法

这里重申一次整个流程, 建议参考 前文提到的博客, 大致如下:

  • 进入页面, 打开开发者工具, 进入 “网络 (Network)” 选项卡
  • 刷新页面, 检视网页对 https://mooc1-1.chaoxing.com/ananas/status/<objectid>?flag=normal 的访问请求 (可以筛选 XHR 类别下的请求)
  • 预览 (Preview) 该请求, 查看到对应的内容 (或者手动模拟请求, 但是需要有相应的权限)
  • 得到一个 JSON 对象, 获取其中 download 属性的值, 应为一个具有 at_, ak_, ad_ 等参数的 URL
  • 在控制台中创建一个 HTML <a> 元素, 其 href 属性为上一步获得的 URL, 需注意替换协议头
    e = document.createElement('a')
    e.href = '...'  // download 处给出的 URL, 需注意替换协议头
    e.target = '_self'
    
  • 模拟点击这个 <a> 元素
    e.click()
    

小结

总之, 很多时候 WEB 相关的问题 (比如获取页面所加载的资源, 获取页面展示信息所使用的 API 等等) 都可以通过检视 (Inspect) 网页的源代码 (HTML + CSS + JavaScript), 最终渲染出来的元素, 以及过程中的网络请求等解决.

比如这次问题中的 “学习通章节文件下载”, 除非学习通在服务器端将文件截图渲染好再递交给用户, 不然用户总是需要下载文件本身, 且用户总是可以检视这个过程, 以得到相应的文件.

就算是学习通在服务器端渲染好文件 (且不说这会给学习通服务器带来多少压力), 我们也总是可以找到唯一标识这个文件的 ID, 并通过一定的 API 获取到这个文件的下载地址. 更何况, 超星目前的网站 (以及其他很多网站) 上代码繁复冗杂, 风格各异, 也许总能从其中找到切入点.


Last modified on 2022-05-03