Skip to content

Course Community

ChangYo edited this page Oct 26, 2026 · 1 revision

选课社区

项 值
平台 course.sjtu.plus
认证 用户 API Key(Authorization: Bearer)
数据方向 只读 + 写(点评、投票、关注、选课记录)
难度 低
最后验证 2026-10-26
证据等级 A(站点自有文档 + 关键端点实测)

选课社区是学生自建的课程点评站,基于 SJTU-jCourse/next。它维护了一份给 Agent 用的 API 参考,接口形态比多数校园私有接口稳定;但站点和文档都来自学生项目,不是学校的教学系统。

相关:jAccount 与校园会话、安全、隐私与合规。

要点

  • 可获取:课程、教师、评分分布、点评、本人选课和关注状态(实测);积分记录、站点公告按文档列出,未看到实际数据。
  • 前置:用户自己在站点生成的 API Key。API Key 以本人身份工作,能读也能写。
  • 注意:点评里的成绩是用户自填的,不是教学信息网的官方成绩;score 与 rating 是两个字段。
  • 没有匿名读接口:不带 Key 的请求一律 401,连公告和筛选接口也一样。[实测 2026-10-26]

数据清单

对象 内容 备注
账号 id、username、email、role /api/auth/me 探活
课程 id、code、name、credit、department、language、target_years、categories、main_teacher 列表项
评分 count、avg、score、distribution(5 元素,1–5 星计数) avg 是均分;score 是站点算出的综合分,算法未公开;列表里的 distribution 实测恒为全 0(抽查 6 门课),真实分布只在详情页
课程详情 last_semester、offered_courses、same_code_courses、same_teacher_courses、notification_level、moderator_remark、my_enrollments、my_review 抽查 12 门课都没有文档写的 teacher_group;my_enrollments/my_review 只在有数据时出现
点评 id、course_id、semester、score、rating、content、moderator_remark、vote、created_at、updated_at score 是自由文本,不是成绩枚举;实测响应没有文档写的 course、user_id
教师 id、code、name、department、title 教师页可按评分排序课程
本人数据 选课记录、关注/忽略课程、本人点评;积分返回 {records, total} 需要 API Key
公告 id、title、body、priority、created_at 字段来自 API 参考;两次实测都返回空数组,没有实际条目可核对

1. 平台架构

部分 Base URL 鉴权 用途
网页 https://course.sjtu.plus/ 邮箱 + 密码 / jAccount 同步 浏览、点评、生成 API Key
API https://course.sjtu.plus/api 用户 API Key 或浏览器会话 本页主体
扩展接口 /api/ext/* 系统 API Key(管理员创建) 站点间集成,个人用不到

Bearer API Key 的校验先于会话校验;带有效 Key 时,写操作跳过 CSRF。[官方] JCourse API Reference


2. 认证

生成 API Key

  1. 站点账号是 用户名@sjtu.edu.cn 形式的交大邮箱:前端把用户名直接拼上 @sjtu.edu.cn,该域名来自站点配置项 auth.email_domain。它和 jAccount 是两套账号。[代码]
  2. 在站点的 API Key 管理页新建一个 Key,明文只显示一次。
  3. 把 Key 存进本机密钥存储,不写进代码、日志或仓库。

对应接口是 GET/POST /api/api-key/(创建 body {"name":"agent"})与 DELETE /api/api-key/{id}。[官方]

GET /user/settings 在 2026-10-26 的实测中不可用:不带斜杠返回 404,带斜杠返回 301 再落到 404。同轮试了 /user/setting、/settings、/user、/user/profile 也都是 404,带 Key 也一样,说明这组路径在当前部署不存在。[实测 2026-10-26]

探活

GET https://course.sjtu.plus/api/auth/me
Authorization: Bearer <api_key>
{"id":1,"username":"u1","email":"u1@example.edu","role":"user"}

不带 Key 时,课程列表、筛选、点评、教师、公告、API Key 管理全部返回 401 {"error":"unauthorized"};站点不提供公开读接口。[实测 2026-10-26,未登录]

Key 不是只读凭证

同一个 Key 可以关注课程、发点评、改点评、投票、改选课记录。只把它交给本人控制的工具,并且写操作前逐次确认目标。[官方]


3. 端点表

Base:https://course.sjtu.plus/api

课程与教师

接口 关键参数 返回
GET /course/filter - credits、departments、categories、target_years、languages、semesters 及计数
GET /course/ q、department、language、categories、target_years、credit、has_review、order_by、ascend、page、page_size 课程分页,order_by 取 rating_score/rating_count/rating_avg
GET /course/hot period=week|month、limit items 为 {course, score};热门度不是评分
GET /course/{id} 路径 详情、授课教师、相关课程、本人状态
GET /course/{id}/review/filter 路径 可选学期与评分
GET /course/{id}/review/trend 路径 [{semester, avg, count}]
GET /teacher/ q、department、title、page、page_size 教师分页
GET /teacher/{id}、GET /teacher/{id}/course 路径 教师详情与其课程

点评

接口 关键参数 返回
GET /course/{id}/review q、semester、rating、order_by=like_count|created_at、page、page_size 课程点评分页
GET /review q、semester、rating、order_by、page、page_size 全站点评;登录后排除已忽略课程
GET /review/{id} 路径 单条点评
POST /review/ body:course_id、rating、content;可选 semester、score 写操作;敏感内容返回 400
PUT /review/{id}、DELETE /review/{id} 路径 + body 写操作;一般是本人或管理员
POST /review/{id}/vote body:vote_type(1 赞、-1 踩、0 取消) 写操作;有每日上限,超限 429
GET /user/{id}/review 路径 + 分页 本人或管理员

个人状态

接口 关键参数 返回
POST /course/{id}/notification body:{"level":0|1|2}(普通、关注、忽略) 写操作
GET /course/followed、GET /course/ignored 分页 关注 / 忽略列表
GET /review/followed 分页 关注课程的点评
GET /course/enrolled - 本人选课记录
POST /course/{id}/enrollment、DELETE /course/enrollment/{id} body:{"semester"} 写操作
GET /user/{id}/point 分页 积分与积分记录
GET /announcement/ - 站点公告

文档还列出 GET/PUT /user/settings;2026-10-26 实测六个路径全部 404,已不列入上表。[实测 2026-10-26]

写操作端点来自官方文档,本页没有执行;POST /review/ 一类请求在提交前要逐次确认目标、内容和影响。[官方]

GET /course/enrollment-sync/start?semester=... 是浏览器 OAuth 式的 jAccount 同步入口,回调在 /course/enrollment-sync/callback;不适合在 Agent 里自动跑。[官方]


4. 响应结构与分页

分页统一为:

{"items": [], "total": 0, "page": 1, "page_size": 20}
  • 默认 page=1&page_size=20。[官方]
  • 数组型过滤条件重复同一个 key:?categories=CORE&categories=ELECTIVE&target_years=2026。
  • 布尔参数用 0/1,前端客户端按这个习惯发请求。

课程列表项:

{
  "id": 123,
  "code": "CS101",
  "name": "数据结构",
  "credit": 3,
  "department": "计算机学院",
  "language": "zh",
  "target_years": ["2026"],
  "categories": ["core"],
  "last_semester": "2025-2026-2",
  "main_teacher": {"id": 10, "name": "教师"},
  "rating": {"count": 12, "avg": 4.3, "score": 4.1, "distribution": [0, 0, 0, 0, 0]}
}

列表项实测要点(2026-10-26):last_semester 也在列表里;rating.distribution 在列表里恒为 [0,0,0,0,0],同一门课的 GET /course/{id} 却返回真实分布(如 [0,0,1,3,197],count 同为 201)。抽查 6 门课(count 66–201)全部如此,要做评分分布必须取详情。[实测 2026-10-26]

点评对象:

{
  "id": 55,
  "course_id": 123,
  "semester": "2025-2026-1",
  "score": "A",
  "rating": 5,
  "content": "...",
  "moderator_remark": "",
  "vote": {"like_count": 3, "dislike_count": 0, "my_vote": 1},
  "created_at": "2026-01-01T00:00:00Z",
  "updated_at": "2026-01-01T00:00:00Z"
}

错误响应

错误统一是 {"error": "..."},例如未登录:

{"error":"unauthorized"}
状态码 含义
400 参数或 body 不合法;点评内容触发敏感词;投票值或关注级别不合法
401 未登录、Key 无效或会话过期
403 无权限、CSRF 失败、账号被限制
404 课程、点评、教师、用户或 Key 不存在
409 重复操作或积分不足
429 限流、验证过于频繁、每日投票上限

[官方]


5. 数据质量

  • rating 与 score:rating 是星级(1–5),score 是点评者填的成绩。做课程推荐只用 rating,把 score 当参考。rating.score 是站点综合分,算法未公开,不要自造解释。
  • 样本量:rating.count 可能是个位数;少于 5 条时不要给「好课/水课」结论,也不要在排序里让低样本课程挤到前面。
  • 热门度:/course/hot 的 score 是活跃度得分,不是评分。period 只有 week/month。
  • 点评时点:点评带 semester 和 created_at;教学安排和给分风格会随学期变化,展示时带上学期。
  • 自填成绩:score 是用户主观填写的,不代表教学信息网记录,也不能用来推断某门课的真实给分。
  • 内容审核:moderator_remark 非空表示被处理过;引用点评时保留原文链接。
  • 评分分布:列表接口的 distribution 全 0,只有详情接口有真实值;把「有分布」当成列表能力会得到全零图。[实测 2026-10-26]
  • score 不是枚举:120 条点评样本里出现空字符串(62 条)、A、90、95、4.0、4.3 等混合取值,字母、百分制、GPA 制都有;不要按固定格式解析,做统计前先归类。[实测 2026-10-26]

6. 常见问题

  1. 401 / 403:Key 被删除或输入错误;先 GET /auth/me。
  2. 写操作返回 400:点评内容触发敏感词;不要反复重试同一段文字。
  3. 429:投票有每日上限,也可能触发站点限流;退避,不要绕过。
  4. CSRF:只有浏览器会话需要;用 API Key 时不带 CSRF 也能写,这更要求 Key 保密。
  5. Key 明文只出现一次:创建后立刻保存,不要指望再查一次。
  6. 忽略的课程从全站点评里消失:这是预期行为,不是接口漏数据。
  7. page_size 上限:文档给出默认 20,没写死最大值;别一次拉全站。
  8. 匿名请求全是 401:这是站点的默认行为,不是 Key 配错;先确认 Key 是否已经带上。
  9. /user/settings 带 Key 也 404:试过六个路径都不通;文档写的路径在当前部署不存在。[实测 2026-10-26]
  10. 详情里没有 teacher_group:文档列为详情字段,抽查 12 门课都没有;按 main_teacher 和 offered_courses 取教师与学期。[实测 2026-10-26]
  11. my_review / my_enrollments 会缺席:只在有数据时出现,缺字段不等于接口失败。[实测 2026-10-26]

7. 最小示例

const API = 'https://course.sjtu.plus/api';

async function searchCourses(key: string, keyword: string) {
  const query = new URLSearchParams({ q: keyword, page: '1', page_size: '20' });
  const response = await fetch(`${API}/course/?${query}`, {
    headers: { Authorization: `Bearer ${key}`, Accept: 'application/json' },
  });
  if (response.status === 401) throw new Error('选课社区 API Key 已失效');
  if (!response.ok) throw new Error(`选课社区 HTTP ${response.status}`);
  const payload = await response.json();
  if (!Array.isArray(payload?.items)) throw new Error('课程列表结构已变化');
  return payload.items;
}

async function courseReviews(key: string, courseId: number) {
  const query = new URLSearchParams({
    order_by: 'like_count',
    page: '1',
    page_size: '20',
  });
  const response = await fetch(`${API}/course/${courseId}/review?${query}`, {
    headers: { Authorization: `Bearer ${key}`, Accept: 'application/json' },
  });
  if (response.status === 401) throw new Error('选课社区 API Key 已失效');
  if (!response.ok) throw new Error(`选课社区 HTTP ${response.status}`);
  const payload = await response.json();
  return Array.isArray(payload?.items) ? payload.items : [];
}

8. 不要做

  • 不要批量发点评、刷票或替他人发点评;这些是社区内容,不是个人数据。
  • 不要在日志、终端输出或错误信息里打印 API Key。
  • 不要把社区评分当成学校对课程质量的评价。
  • 不要绕过每日投票上限、敏感词审核或站点限流。

9. 证据与来源

  • API Key 可用、/api/auth/me 与课程搜索返回 200:[实测 2026-10-25,本人 Key,只读]
  • 端点、参数、字段、分页、错误码:[官方] JCourse API Reference、SJTU-jCourse/next
  • 带 Key 实测:/auth/me、课程列表(total:100)、筛选、热门、教师、课程详情、点评(total:201)、趋势、点评筛选均 200;/course/enrolled、/announcement/ 返回空数组:[实测 2026-10-26,本人 API Key,只读];记录未入库。
  • 积分接口返回 {records, total}(本人 total: 0);120 条点评样本的 score 混合空串、字母、百分制与 GPA:[实测 2026-10-26,本人 API Key,只读]
  • 未登录时已试接口 401 {"error":"unauthorized"}、/user/settings 返回 404、站点首页可访问:[实测 2026-10-26,未登录,只读探测]
  • 服务入口:[官方] 选课社区

变更记录

  • 2026-10-25:首版。按项目内 API 参考整理端点,只读部分已实测,写操作未执行。
  • 2026-10-26:补匿名探测结果与错误响应表;确认积分字段、公告为空、teacher_group 12 门课均无、score 混合取值、注册邮箱域来自 auth.email_domain。
  • 2026-10-26:带 Key 复测关键端点,证据等级 B → A;更正三处文档与实现不符(列表 distribution 全 0、无 teacher_group、/user/settings 不存在)。

Clone this wiki locally