Skip to content

Campus Info

ChangYo edited this page Oct 26, 2026 · 3 revisions

校园公开信息

项 值
平台 news.sjtu.edu.cn、jwc.sjtu.edu.cn 等
认证 无(公开网页)
数据方向 只读
难度 低
最后验证 2026-10-25
证据等级 C(公开网页结构,随时会变)

这页给出两个可运行的采集示例:交大新闻和教务处通知。其他校园信息源(图书馆、班车、食堂、空教室、场馆)没有稳定公开契约,统一放在待验证清单和资料来源。第二课堂有独立接口,见第二课堂。

Warning

下面的方法依赖 2026-10-25 观察到的 HTML 结构,没有 API 契约。学校改版后解析会失败。解析失败时应保留旧缓存并提示,不要把它当成「没有新闻」。

依赖:npm i cheerio。示例使用 Cheerio 解析 HTML;也可以使用 DOMParser 或正则,但需要自行复核选择器。


1. 交大新闻

列表

入口:https://news.sjtu.edu.cn/

列表链接形如 /zhxw/20261021/226815.html;标题在 <a> 文本里。[实测 2026-10-25]

import * as cheerio from 'cheerio';

const BASE = 'https://news.sjtu.edu.cn';

export async function listNews() {
  const response = await fetch(BASE, { redirect: 'follow' });
  if (!response.ok) throw new Error(`news list HTTP ${response.status}`);
  const $ = cheerio.load(await response.text());

  const items = new Map<string, { title: string; url: string }>();
  $('a[href^="/zhxw/"]').each((_, element) => {
    const href = $(element).attr('href');
    const title = $(element).text().replace(/\s+/g, ' ').trim();
    if (!href || !title) return;
    items.set(href, { title, url: new URL(href, BASE).href });
  });
  return [...items.values()];
}

要点:

  • 用 Map 去重:首页同一个链接可能出现多次。
  • 只收 /zhxw/ 开头的链接;/jdyw/ 等导航链接不属于新闻正文。
  • 更早的新闻走 /zhxw/index.html 的分页;先抓首页,不要一上来全站翻页。

正文

文章页结构(2026-10-25):

  • 标题:.Article-title(回退 <title>,去掉 _综合新闻_上海交通大学新闻学术网 后缀)。
  • 正文:.Article_content。
export async function readNews(url: string) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`news article HTTP ${response.status}`);
  const $ = cheerio.load(await response.text());
  $('script, style').remove();

  const title =
    $('.Article-title').text().replace(/\s+/g, ' ').trim() ||
    $('title').text().split('_')[0]!.trim();
  const body = $('.Article_content').text().replace(/\s+/g, ' ').trim();
  if (!title || !body) throw new Error('新闻结构已变化:标题或正文为空');

  return { title, body, url };
}

正文里的图片是相对路径 /resource/upload/...;要显示时用 new URL(src, BASE) 补全,并遵守图片版权。


2. 教务处通知

列表

入口:https://jwc.sjtu.edu.cn/xwtg/tztg.htm

列表项有两类链接:

  • ../info/1222/129211.htm
  • ../content.jsp?urltype=news.NewsContentUrl&wbtreeid=1222&wbnewsid=129171

两者都要收;用 new URL(href, listUrl) 解析相对路径。[实测 2026-10-25]

const JWC_LIST = 'https://jwc.sjtu.edu.cn/xwtg/tztg.htm';

export async function listJwcNotices() {
  const response = await fetch(JWC_LIST);
  if (!response.ok) throw new Error(`jwc list HTTP ${response.status}`);
  const $ = cheerio.load(await response.text());

  const items = new Map<string, { title: string; url: string }>();
  $('a[href*="/info/"], a[href*="content.jsp"]').each((_, element) => {
    const href = $(element).attr('href');
    const title = $(element).text().replace(/\s+/g, ' ').trim();
    if (!href || !title || title === '通知通告') return;
    const url = new URL(href, JWC_LIST).href;
    items.set(url, { title, url });
  });
  return [...items.values()];
}

分页:

  • 列表底部有 tztg/236.htm、tztg/235.htm 这类链接;找「下页」或 a[href^="tztg/"]。
  • 只抓最近 N 页(比如 2 页);不要全站翻。
  • 公告可能带附件(PDF/DOC);正文页里找 a[href$=".pdf"]、.doc、.docx、.xls,按需下载。

正文

文章页结构(2026-10-25):

  • 标题:.content-title(回退 <title>,去掉 -上海交通大学教务处 后缀)。
  • 正文:.v_news_content。
export async function readJwcNotice(url: string) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`jwc article HTTP ${response.status}`);
  const $ = cheerio.load(await response.text());
  $('script, style').remove();

  const title =
    $('.content-title').text().replace(/\s+/g, ' ').trim() ||
    $('title').text().split('-')[0]!.trim();
  const body = $('.v_news_content').text().replace(/\s+/g, ' ').trim();
  if (!title || !body) throw new Error('教务通知结构已变化:标题或正文为空');

  return { title, body, url };
}

3. 组合成一个最小的通知聚合器

async function collect() {
  const news = (await listNews()).slice(0, 10);
  const notices = (await listJwcNotices()).slice(0, 10);

  const enriched = [];
  for (const item of [...news, ...notices]) {
    try {
      const detail = item.url.includes('jwc.sjtu.edu.cn')
        ? await readJwcNotice(item.url)
        : await readNews(item.url);
      enriched.push({ ...item, ...detail, fetchedAt: new Date().toISOString() });
    } catch (error) {
      // 单条失败不阻塞整体;保留标题/链接,标 error
      enriched.push({
        ...item,
        body: null,
        error: error instanceof Error ? error.message : String(error),
        fetchedAt: new Date().toISOString(),
      });
    }
  }
  return enriched;
}

存储建议:

  • 主键用 URL;保留 title、body、fetchedAt、source。
  • 列表页只用来发现新 URL;正文按 URL 增量抓,抓过的不要每次重抓。
  • 解析失败时保留旧正文,标 stale/error;不要删。

4. 常见问题

  1. 页面没有 API 契约:选择器变化后解析结果会为空;必须保留「解析失败」状态。
  2. 相对链接:新闻 /zhxw/...、教务 ../info/...;统一用 new URL(href, base)。
  3. 重复链接:首页/列表里同一篇可能出现多次;按 URL 去重。
  4. 编码:这两站当前页面是 UTF-8;如果遇到乱码,先看 Content-Type/charset,不要硬转。
  5. 附件:教务通知常带 PDF/DOC;正文抓不到时,附件可能是关键信息。
  6. 分页:新闻/教务都有分页;只抓最近 N 页,别全站扫。
  7. 改版:选择器是 2026-10-25 的观察值;改版后先看页面结构,再改选择器。
  8. 频率:新闻/教务没有公开限流,但不要高频轮询;小时级足够。
  9. 版权/隐私:新闻正文、通知附件不要重新分发;个人工具内展示,保留原文链接。

5. 其他源

以下源没有稳定公开契约,不在本页给解析代码;需要时按待验证清单逐项验证,参考实现见资料来源:

  • 图书馆借阅/座位/研讨间:需要校园会话或读者账号。
  • 班车时刻/实时位置:可能以公告/图片发布。
  • 食堂菜单/人流:更新频率和数据源不稳定。
  • 空教室:依赖学期/教学楼参数。
  • 体育场馆:只读场地图/订单可以研究;不要自动预约。

6. 证据与来源

  • 新闻列表/正文选择器:[实测 2026-10-25,news.sjtu.edu.cn]
  • 教务通知列表/正文选择器:[实测 2026-10-25,jwc.sjtu.edu.cn/xwtg/tztg.htm]
  • 其他源:[社区] SJTU-Geek/sjtu-mcp-server、openclaw-sjtu(只作线索,未在本页验证)

变更记录

  • 2026-10-25:重写。只保留新闻、教务通知两个可执行源;其余移到待验证/来源页。
  • 2026-10-26:第二课堂移出本页,改链到独立平台手册。

Clone this wiki locally