← FC Coder · HomePhase 02 · Lesson 24 · 90 min
Lesson24
Phase Two · Fantasy Builder · Matchday 24 · Winter Camp · Day 1
Kaggle 数据导入
15000 人进场
Today's 3 Jobs · 今天这三件事
- 01新建 scripts/import-kaggle.ts · 读 CSV 写 JSONNode 第一次进场
- 02pnpm tsx 跑一次 · 15000 人到位终端看 parsed N players
- 03🌟 .slice(0, 100) 性能戏 + 找哈兰德DOM 不能塞太多
🌟 寒假集训第 1 节 · 90 分钟。Phase 1 父子手写 22 人 · 今天进货 —— Node 脚本 + 一行命令 · 15000 人到位。Node 是工程的另一半:浏览器之外的赛场 · 跑脚本 · 读硬盘。
Concept · 第 1 个新概念
Node = 另一个赛场
浏览器跑给用户看 · Node 跑给程序员处理文件。
import { readFile, writeFile } from 'node:fs/promises';
// 浏览器没有 fs · 这只在 Node 跑
// 浏览器没有 fs · 这只在 Node 跑
浏览器
用户点开网页 · DOM / React / 不能读硬盘
Node
程序员开终端 · 跑脚本 · 能读 / 写文件
今天
写 Node 脚本 · 把 CSV 变 JSON
`pnpm tsx scripts/import-kaggle.ts` —— 翻译机让 Node 直接跑 TS。
Concept · 第 2 个新概念
CSV → JSON · 字段映射 + 清洗
Kaggle 用 CSV · 我们用 JSON · 中间一段代码桥接。
// CSV 解析:逗号分隔 · 引号包字段
"哈兰德","ST,LW","曼城" → 3 个字段(不是 4)
"哈兰德","ST,LW","曼城" → 3 个字段(不是 4)
Kaggle
short_name, overall, player_positions, ...
我们的
name, rating, position, ...
清洗
位置取第 1 个 · 空俱乐部 → "Free Agent"
详细字段对照见 docs/ethics/kaggle-snapshot.md。
Roster · 今天 3 个新工具
Node · pnpm tsx · CSV → JSON
抄着用 · Step 8 看到 parsed N players 是今天的「哇」。
- 01Node.js另一个赛场 —— 跑 JS / TS 但不在浏览器 · 在终端 · 能读硬盘。浏览器读不了硬盘是安全设计。Node 给程序员用。
- 02pnpm tsx file.ts翻译机 —— Node 不认 TS · tsx 直接跑(不用先编译)。2024 起业内共识 · 比 ts-node 更快。
- 03CSV → JSON清洗 —— 逗号分隔的表格 · 字段映射 + 默认值。短名 / 评分 / 位置 / 国家 / 俱乐部。NULL → "Free Agent"。
Half 2 · 在屏幕上(集训 · 90 min)
脚本骨架 · 解析 · 跑一次 · 接到 fantasy
做完一步就点 ✓。Step 8 终端 parsed 那一刻是今天的「哇」。
01脚本骨架 · 读文件
01Min
确认 .local/kaggle/players.csv 已在
爸爸提前 1 周从 Kaggle 下好。Cursor 左树看到(.local 灰色 · gitignore 挡)。
02Min
新建 scripts/import-kaggle.ts
右键 → New Folder → scripts · 里面 New File → import-kaggle.ts。第一行 #!/usr/bin/env tsx(可选 · 仪式感)。
03Min
import readFile / writeFile / resolve · 写 Player type
import { readFile, writeFile } from 'node:fs/promises'; import { resolve } from 'node:path'; type Player = { name, rating, position, nationality, club: string }。
04Min
写 main 骨架 · pnpm tsx 跑一次 · 看 chars 数
const CSV_PATH = process.argv[2] ?? '.local/kaggle/players.csv'; async function main() { const text = await readFile(resolve(process.cwd(), CSV_PATH), 'utf-8'); console.log(`read ${text.length} chars`); } main().catch(...)。终端 pnpm tsx scripts/import-kaggle.ts · 看到 read 18M+ chars。
02CSV 解析 + 字段映射
05Min
抄 parseCsv 函数(50 行 · 处理引号)
课文里的整段抄进去 · 别展开。本质点是脚本跑通 · 不是 parser 实现。Phase 3 用 papaparse 库就免抄。
06Min
替换 main · 用 parseCsv + 字段映射
header = rows[0]; idx = { short_name, overall, player_positions, nationality_name, club_name } 各 indexOf。for (r = 1; ...) 读每行 · 清洗:position split(',')[0] · club 空 → 'Free Agent' · rating Number()。NaN / 缺名字 跳过。
07Min
writeFile 写到 app/data/players-full.json
await writeFile(resolve(process.cwd(), 'app/data/players-full.json'), JSON.stringify(players, null, 2), 'utf-8')。console.log 出 parsed N players + wrote 路径。
03🌟 跑一次 · 15000 人
08Min
🌟 pnpm tsx scripts/import-kaggle.ts
终端跑。应该看到 parsed 15000+ players + wrote app/data/players-full.json。今天的「哇」。
09Min
Cursor 打开 app/data/players-full.json · 看前几行
几 MB 文件 · 打开稍慢。看前几行是不是 [{ name, rating, position, ... }, ...]。注意:全英文。
04性能戏 + 找哈兰德
10Min
lib/players.ts 加 playersFull + playersTop100
import fullData from '@/app/data/players-full.json'; export const playersFull: Player[] = fullData as Player[]; export const playersTop100 = playersFull.slice().sort((a,b) => b.rating - a.rating).slice(0, 100)。
11Min
fantasy/page.tsx 改用 playersTop100
import { playersTop100 as players } from '@/lib/players' 替原来的 import { players } from ...。刷新 /fantasy 看 100 张顶级球员卡。顺畅。
12Min
在 players-full.json 搜 Haaland
Cursor Cmd+F 在 JSON 里搜 Haaland(英文)。E. Haaland · 91 · ST · Norway · Manchester City。
13Min
(可选)临时切到 playersFull 看卡顿
改 import 用 playersFull · 浏览器卡 1-3 秒。看清楚 DOM 不能塞太多。改回 playersTop100。Phase 3+ 虚拟列表才解。
05截图 + 收尾
14Min
📸 截图战利品
终端 parsed 15234 + Cursor 打开 players-full.json 头几行。存 2026-XX-XX-15000人进场.png · Phase 2 第九张。
Half Time · 中场 · 讲给爸爸听
4 题 · 重点:两个赛场
第 1 题答得出 = Node 心智到了。
01Node 和浏览器差在哪?为什么浏览器不能直接读硬盘文件?Hint ↓
两个赛场。浏览器读不了硬盘是安全设计 —— 不然任何网站都能偷你电脑文件。
02CSV 为什么要双引号?给一个例子。Hint ↓
字段里有逗号 · 用引号包起来不被错切。如 'ST,LW' 包成一个字段不被切成两个。
03pnpm tsx 是干什么的?Hint ↓
翻译机 —— 直接跑 TS · 不用先编译成 JS。Node 自己不认 TS · tsx 帮翻译。
04为什么我们不把 players-full.json commit 进仓库?Hint ↓
大 + 衍生品。脚本 + 数据来源记录足够 · 每台机器自跑。仓库干净。
Player Rating · 本课温度计
给「15000 人进场」打个分
说真话。爸爸会看到。
今天难度Difficulty
0
今天开心Fun
0
Final Whistle · 终场哨
工程世界另一半开门 —— 一个命令 · 15000 人到位。
还有 14 步没打勾。Step 8 终端 parsed N players 那一刻今天就过。剩下下次集训日补。