资讯详情

鸿蒙教务查询实战:JSoup解析课表与成绩的课程设计

📅 2026/10/7 23:16:52 | 华诺云谱 👁 阅读
鸿蒙教务查询实战:JSoup解析课表与成绩的课程设计
简介这是一份面向高校学生与鸿蒙开发初学者的课程设计资源围绕华为HarmonyOS平台结合Java库JSoup实现教务信息查询功能帮助开发者在安卓替代方案中掌握跨平台应用构建思路。压缩包共183个文件约3.1MB以38个java源码、64个xml布局与配置、50个png图片资源为主另含12个json、7个jpg及gradle构建脚本、har包与jar依赖等覆盖工程配置、界面资源与核心逻辑目录结构完整便于按模块查阅。资源重点演示鸿蒙开发环境搭建、JSoup集成与HTML解析、网络请求与HTTPS安全处理、课程表与成绩等数据提取展示并涉及分布式能力探索与测试调试思路适合作为课程设计参考或鸿蒙入门练手项目。目前已有450人学习下载可帮助读者理解如何将既有Java技术栈迁移到鸿蒙生态提升跨平台开发能力。1. 鸿蒙教务查询软件用 JSoup 把课表和成绩抓进 HarmonyOS期末前一周室友还在用浏览器反复登录教务系统、手动抄课表和成绩我已经把查询结果直接渲染在鸿蒙手机的应用里了。这个课程设计标题说的就是这件事在 HarmonyOS 上做一个教务查询客户端用 JSoup 解析教务系统返回的 HTML把课表、成绩、考试安排结构化后展示出来。它解决的是「教务系统只有网页版、没有开放 API」这个现实问题适合正在做鸿蒙课程设计、想找一个能跑通又有技术含量的题目的同学。核心链路只有三步登录拿 Cookie、请求目标页面、JSoup 解析 DOM。难点不在鸿蒙 UI而在登录态维持和 HTML 结构变化后的容错。下面按我实际做过的顺序拆开讲。2. 先想清楚为什么用 JSoup 而不是等官方接口2.1 教务系统的现实约束决定了技术选型绝大多数高校教务系统是十几年前的老架构页面由服务端渲染返回的是完整 HTML没有 REST 接口也没有 JSON。想拿数据只有两条路一是模拟浏览器发请求把 HTML 抓回来自己解析二是用 WebView 加载页面再注入 JS 提取 DOM。前者轻、可控、省电后者重但能绕过部分 JS 加密。JSoup 属于前者。它是一个 Java 的 HTML 解析库能像 jQuery 一样用 CSS 选择器定位元素select(table#scoreList tr)这种写法直接对应页面结构。鸿蒙的应用开发主语言是 ArkTS但 HarmonyOS 支持通过 Native API 或三方库方式调用 Java 能力课程设计里更常见的做法是把 JSoup 的解析逻辑放在一个 Java 模块里或者干脆用鸿蒙的网络能力拿到 HTML 字符串后用移植版的解析逻辑处理。选 JSoup 的核心理由是「页面结构即接口」。教务系统的表格、div、input的name属性相对稳定改版频率低用选择器抓取比逆向加密参数省事得多。热搜里常出现的 gradle 配置、gradle 离线包这些问题在做这个项目时也会遇到——因为 JSoup 是 Java 生态的库引入它就要处理依赖管理。2.2 鸿蒙侧的网络请求与登录态维持鸿蒙的网络能力用ohos.net.http模块发 POST 请求拿登录后的 Cookie 是第一步。教务系统登录一般是表单提交字段通常是username、password、encoded之类具体要看目标系统的登录页源码。import http from ohos.net.http; // 登录请求表单格式提交拿到 Set-Cookie async function login(baseUrl: string, user: string, pwd: string): Promisestring { const httpRequest http.createHttp(); const resp await httpRequest.request(${baseUrl}/loginAction.do, { method: http.RequestMethod.POST, header: { Content-Type: application/x-www-form-urlencoded }, extraData: username${user}password${pwd}loginType1, // 关键手动管理 Cookie不依赖系统自动存储 expectDataType: http.HttpDataType.STRING }); // 从响应头里取 Set-Cookie后续请求带上 const cookie resp.header[set-cookie] as string; httpRequest.destroy(); return cookie; }这段代码的逻辑是用 POST 把账号密码按表单格式发出去服务端验证通过后在响应头Set-Cookie里下发会话标识。参数说明上Content-Type必须是application/x-www-form-urlencoded否则服务端收不到字段extraData拼接时要注意 URL 编码密码里如果有、这类字符不编码会截断。拿到 Cookie 后后续每次请求都要在 header 里带上Cookie: xxx否则会被重定向回登录页。提示部分教务系统登录时会带一个动态的encoded参数由页面上的 JS 生成。遇到这种情况先用 WebView 加载登录页通过runJavaScript取出该值再提交不要硬编码。2.3 用 JSoup 解析课表 HTML 的最小示例假设已经拿到课表页面的 HTML 字符串解析逻辑如下。这里用 Java 写因为 JSoup 原生是 Java 库课程设计里可以放在独立模块也可以参考社区移植方案在 ArkTS 侧调用。import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class ScheduleParser { public static void parse(String html) { Document doc Jsoup.parse(html); // 课表通常是 table每行一门课选择器按实际页面调整 Elements rows doc.select(table#kbtable tr); for (Element row : rows) { Elements cells row.select(td); if (cells.size() 3) continue; // 跳过表头或空行 String courseName cells.get(1).text().trim(); String classroom cells.get(2).text().trim(); System.out.println(courseName classroom); } } }逻辑说明Jsoup.parse把字符串转成可查询的 DOM 树select用 CSS 选择器定位。参数上table#kbtable里的#kbtable是页面里表格的 id实际项目要打开教务系统页面按 F12 看真实 id 或 class。cells.get(1)的下标取决于表格列顺序不同学校不一样必须对着页面数。text()会自动去掉标签只留文本trim()处理多余空格。这一步最容易翻车的地方是编码。教务系统常用 GBK如果请求时按 UTF-8 解码中文会变乱码。解决办法是在请求头里声明Accept-Charset或者拿到字节流后用new String(bytes, GBK)转换。3. 从登录到渲染把查询链路在鸿蒙上跑通3.1 工程结构与 gradle 依赖配置课程设计通常是一个 HarmonyOS 工程加一个 Java 解析模块。如果解析逻辑放在 Java 侧build.gradle里要加 JSoup 依赖dependencies { // JSoup 核心库用于 HTML 解析 implementation org.jsoup:jsoup:1.17.2 }参数说明版本号选一个稳定版即可1.17.x 对 Java 8 兼容良好。热搜里「gradle 离线包」「gradle 打包打半天」的问题多半是依赖下载卡住。解决办法是配置国内镜像仓库或者提前把 jar 下好放进libs目录用implementation files(libs/jsoup-1.17.2.jar)引入。gradle的repositories块里把mavenCentral()换成镜像地址能明显提速。注意鸿蒙工程默认用 hvigor 构建Java 模块和 ArkTS 模块的依赖管理是分开的。别把 JSoup 直接写进鸿蒙主模块的依赖里放错位置会报找不到符号。3.2 成绩查询的解析与数据建模成绩页和课表页结构不同通常是一个带表头的表格每行包含课程名、学分、成绩、绩点。解析时先定位表头确认列顺序再逐行取值。public class ScoreParser { public static void parse(String html) { Document doc Jsoup.parse(html); Elements rows doc.select(table#scoreTable tbody tr); for (Element row : rows) { Elements tds row.select(td); if (tds.size() 4) continue; String name tds.get(1).text(); String credit tds.get(2).text(); String score tds.get(3).text(); // 只保留数字成绩过滤“优秀”“良好”这类等级制 if (score.matches(\\d(\\.\\d)?)) { System.out.println(name credit score); } } } }逻辑说明tbody tr比直接tr更精确能避开表头行。matches用正则过滤非数字成绩因为很多学校体育、选修课是等级制直接算 GPA 会抛异常。参数上tds.get(1)到get(3)的下标同样要按实际页面核对有的系统第一列是序号有的没有。数据建模建议定义一个Course类字段包括名称、学分、成绩、绩点解析完存进ListCourse再通过鸿蒙的State或AppStorage传给 UI 层渲染。这样解析和展示解耦页面改版时只改解析器。3.3 鸿蒙 UI 侧渲染课表与成绩拿到结构化数据后鸿蒙侧用List或Grid渲染。课表适合Grid成绩适合List。Component struct ScoreList { State scores: ScoreItem[] []; build() { List({ space: 8 }) { ForEach(this.scores, (item: ScoreItem) { ListItem() { Row() { Text(item.name).layoutWeight(1).fontSize(16) Text(item.score).fontSize(16).fontColor(#E64545) }.width(100%).padding(12) } }, (item: ScoreItem) item.name) }.width(100%) } }逻辑说明State修饰的数组变化会触发 UI 刷新ForEach的第三个参数是 key 生成函数用课程名做 key 能避免重复渲染。参数上layoutWeight(1)让课程名占满剩余空间成绩靠右对齐。数据从解析层传过来时注意线程切换——网络和解析不能在主线程做用TaskPool或Worker放到后台完成后回主线程更新State。4. 避坑与排查教务查询最容易翻车的五个点4.1 登录成功但后续请求跳回登录页现象登录接口返回 200但请求课表时拿到的 HTML 是登录页。原因Cookie 没带上或者带上了但格式不对。解决检查请求头里Cookie字段是否完整有些系统要求JSESSIONID和另一个route字段都带。用抓包工具对比浏览器请求和你的请求逐字段对齐。4.2 中文全部变成乱码现象解析出来的课程名是「课ç¨」这类字符。原因教务系统用 GBK 编码而请求或解析时按 UTF-8 处理。解决在拿到响应字节后显式用new String(bytes, Charset.forName(GBK))解码或者在 JSoup 解析前先转好字符串。鸿蒙侧http请求如果直接拿字符串要在header里加Accept-Charset: gbk。4.3 选择器今天能用明天就抓不到现象select(table#kbtable tr)突然返回空。原因教务系统改版id 或 class 变了或者页面结构从 table 改成了 div。解决把选择器写成多套备选按优先级尝试解析前先判断doc.select(...).isEmpty()为空时记录原始 HTML 到日志方便定位。别把选择器硬编码在一个地方抽成常量集中管理。4.4 gradle 同步失败导致 JSoup 引入不了现象build.gradle里加了依赖同步时报Could not resolve org.jsoup:jsoup。原因网络问题或仓库地址不可达。解决换国内镜像仓库或者下载 jar 手动放进libs目录用files方式引入。热搜里「gradle 离线包」说的就是这个场景提前配好能省很多时间。4.5 解析在主线程执行导致界面卡死现象点击查询后界面冻结几秒然后才出结果。原因网络请求和 HTML 解析都在主线程。解决把整个查询链路包进TaskPool.execute解析完把结果通过sendData回传主线程。鸿蒙对主线程耗时操作有严格限制超过阈值会直接抛异常。5. 进阶让解析器扛住改版用配置化选择器兜底做到能查之后真正决定这个课程设计能不能拿高分的是「容错」。教务系统改版是常态把选择器写死在代码里改一次就要重新编译。我的习惯是把选择器抽成一份配置放在resources/rawfile下解析时读取配置。{ schedule: { table: table#kbtable, table.kb, table[class*schedule], row: tr, nameIndex: 1, roomIndex: 2 }, score: { table: table#scoreTable, table[class*score], row: tbody tr, nameIndex: 1, creditIndex: 2, scoreIndex: 3 } }解析器按逗号分隔依次尝试每个选择器命中第一个非空结果就用。nameIndex这类下标也配置化改版时只改 JSON 不重新编译。这个思路在多个学校系统上验证过能覆盖大部分结构微调。验证方法上我一般准备三份 HTML 样本正常页面、改版后页面、登录失效页面写单元测试分别断言解析结果。正常页面断言课程数大于 0改版页面断言不抛异常且能降级登录失效页面断言能识别出「请重新登录」关键字并提示用户。场景输入期望行为正常课表标准 HTML解析出课程列表结构改版id 变化备选选择器命中登录失效登录页 HTML识别并提示重新登录编码异常GBK 字节流正确解码中文最后说个血泪经验别在解析器里写System.out.println调试完就留着鸿蒙打包时这些输出会拖慢启动。调试用日志框架上线前关掉。这个课程设计的技术含量不在 UI 多花哨而在你能不能把「登录态 编码 选择器容错」这三件事做扎实。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑