智慧教育平台教材下载器 (smartedu-downloader)
从 国家中小学智慧教育平台(basic.smartedu.cn)下载教材资源:
- 听力音频(MP3,如英语教材的 Listening)
- 教材电子版(PDF 本体)
背景 / 为什么需要登录
- 平台的资源清单 API 无需登录即可访问,但 2024 年 8 月后,实际文件 CDN(
r*-ndr-private.ykt.cbern.com.cn)需要X-Nd-Auth鉴权头才能下载。 - 该鉴权头由登录后 token 里的
access_token+mac_key通过 HMAC-SHA256 生成。 - 登录会触发腾讯滑块验证码,无法自动破解。本版支持两种方式:
- 扫码登录(推荐):不设账号密码,浏览器弹出后用户用手机 App 扫码即完成登录,无需拖滑块。
- 账号登录:脚本自动填账号密码 + 用户手动拖动滑块。
使用流程
1. 收集参数(向用户询问)
必需:
- 一个或多个教材链接(https://basic.smartedu.cn/tchMaterial/detail?...contentId=<CID>...)
从每个链接的 URL 中提取 contentId 参数值作为 cid。账号密码可选(不提供则扫码登录)。
2. 先探测教材类型(无需登录,推荐先做)
在真正下载前,先用文件服务器镜像确认每个教材是「听力音频」还是「纯PDF」,以及标题,便于给用户预告:
node -e '
const CID="<contentId>";
(async()=>{
for (const s of ["s-file-1","s-file-2","s-file-3"]) {
try {
const r = await fetch(`https://${s}.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/${CID}.json`);
if(!r.ok) continue;
const d = await r.json();
const hasPdf=(d.ti_items||[]).some(it=>it.ti_format==="pdf"||it.lc_ti_format==="pdf");
console.log("标题:", (d.global_title&&d.global_title["zh-CN"]), "| PDF:", hasPdf);
break;
} catch(e){}
}
const a = await (async()=>{for(const s of ["s-file-1","s-file-2","s-file-3"]){try{const r=await fetch(`https://${s}.ykt.cbern.com.cn/zxx/ndrs/resources/${CID}/relation_audios.json`);if(r.ok)return await r.json();}catch(e){}}return[];})();
console.log("听力数量:", Array.isArray(a)?a.length:0);
})();
'
3. 确保依赖就绪
脚本依赖 playwright(需已安装 chromium 浏览器)。检查:
node -e "require('playwright'); console.log('playwright OK')"
若缺失,需在隔离的 node workspace 安装:npm i playwright && npx playwright install chromium(按运行环境的隔离规则调整路径与 NODE_PATH)。
4. 运行下载脚本
所有参数通过环境变量传入 scripts/smartedu_downloader.js:
| 变量 | 说明 |
|---|---|
SMARTEDU_PHONE / SMARTEDU_PASS |
可选。提供则自动填账号密码;不提供则纯扫码登录(推荐) |
SMARTEDU_JOBS |
JSON 数组字符串(可选,与 JOBS_FILE 二选一) |
SMARTEDU_JOBS_FILE |
JSON 数组文件路径(推荐,清单较大时避免 env 参数过长) |
SMARTEDU_OUTPUT_DIR |
输出根目录(默认 ./smartedu_downloads) |
SMARTEDU_MODE |
audio|pdf|auto(默认 auto:有听力则下听力,否则下PDF) |
SMARTEDU_BATCH_DELAY_MS |
每本之间最小间隔,默认 3000(节流,保护账号) |
SMARTEDU_COOLDOWN_EVERY |
每 N 本后冷却,默认 10 |
SMARTEDU_COOLDOWN_MS |
冷却时长,默认 15000 |
jobs 元素结构:{"cid":"<contentId>","name":"<可选,文件名>","dir":"<可选,子目录如 小学/英语/人教版>"}。
- name 省略时自动用教材官方标题命名。
- dir 用于按 学段/学科/版本 分子目录输出;省略则平铺到输出根目录。
- 断点续传:目标文件已存在且大小合理时自动跳过,可随时中断重跑。
示例(扫码登录 + 从文件读清单 + 按子目录输出):
SMARTEDU_OUTPUT_DIR="/输出/目录" SMARTEDU_MODE="pdf" \
SMARTEDU_JOBS_FILE="/路径/jobs.json" \
NODE_PATH="<node_modules 路径>" node scripts/smartedu_downloader.js
jobs.json 示例:
[
{"cid":"b7ca9536-ccd7-a4db-56b3-971645c54515","dir":"小学/英语/人教版"},
{"cid":"540ac93d-67fc-4353-9e49-1ef20d02b5a4","dir":"高中/数学/人教A版"}
]
也可用环境变量直接传小清单:
SMARTEDU_PHONE="手机号" SMARTEDU_PASS="密码" \
SMARTEDU_MODE="auto" \
SMARTEDU_OUTPUT_DIR="/输出/目录" \
SMARTEDU_JOBS='[{"cid":"b7ca9536-ccd7-a4db-56b3-971645c54515"}]' \
NODE_PATH="<node_modules 路径>" node scripts/smartedu_downloader.js
重要:脚本以前台方式运行(headless:false),会弹出真实浏览器窗口。运行后提示用户:
- 若为扫码登录:> 请用手机 App 扫码登录(也可点「登录」后拖滑块),登录成功后页面自动跳转,脚本自动取 token 并下载。
- 若为账号登录:> 浏览器已打开,账号密码已自动填好。请你:1. 点击蓝色「登录」按钮 → 2. 拖动滑块完成验证码 → 3. 等待自动跳转。
脚本最多等待 6 分钟让用户完成登录。不要用后台方式运行,否则无法观察进度、任务易丢失。
5. 校验结果
下载后校验文件完整性:
- MP3:文件头为 ID3(494433) 或帧头 fffb/fff3,大小 > 1KB
- PDF:文件头 %PDF-,末尾 1024 字节内含 %%EOF
然后用 present_files 把输出目录展示给用户。
关键技术细节(供排错)
- token 存储位置:登录后写入 localStorage,key =
ND_UC_AUTH-e5649925-441d-4a53-b525-51a2f1c4e0a8&ncet-xedu&token - token 是嵌套结构:
{value:"<json字符串>", expire:...},真正的access_token/mac_key在value里,需先JSON.parse外层再解包.value(脚本已处理)。 - X-Nd-Auth 生成:
MAC id="{access_token}",nonce="{ts}:{rand}",mac="{HMAC_SHA256(mac_key, "{nonce}\n{GET}\n{host}\n{path}\n")}"(mac 为 hex) - 登录页表单(账号登录):手机号
#username,密码#tmpPassword,协议勾选#agreementCheckbox - 常见坑1:轮询时若用户还在 auth 域名(登录页),不能强制
page.goto跳转,否则验证码界面被冲掉,用户无法操作。脚本仅在离开 auth 域名后才检查/跳转。 - 常见坑2:用户扫码很快时,自动填账号密码可能失败(页面已跳转)。脚本已将自动填字包在 try/catch 中,失败不中断,直接进入取 token 流程。
- 常见坑3:有的教材(非英语学科,如语文/数学/道法/历史/地理)没有听力音频(
relation_audios为 0),此时应下 PDF 本体。auto模式会自动处理。 - 资源清单 API:
- 教材详情(含PDF):
https://s-file-{1,2,3}.ykt.cbern.com.cn/zxx/ndrv2/resources/tch_material/details/{CID}.json - 听力清单:
https://s-file-{1,2,3}.ykt.cbern.com.cn/zxx/ndrs/resources/{CID}/relation_audios.json - 文件 CDN:
r{1,2,3}-ndr-private.ykt.cbern.com.cn(需鉴权) - token 有效期内可连续下载多个资源,无需重复登录。
- 全站目录(无需登录):
https://s-file-1.ykt.cbern.com.cn/zxx/ndrs/resources/tch_material/version/data_version.json→ 4 个分片part_100..103.json(共约 3600+ 条,含每条 contentId/标题/学科/版本标签),可用于批量生成 jobs。
安全与隐私
- 账号密码(如使用)仅用于当次登录,通过环境变量传入,不要写入任何文件或日志。
- 下载所得为教材公开资源,供用户个人学习使用。