Skip to content

Commit d75a7e8

Browse files
committed
feat: works with new cais
1 parent 984d2d6 commit d75a7e8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+195
-56
lines changed

crawler_new.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import * as fs from 'fs';
2+
import {writeFileSync} from 'fs';
3+
import {sort} from "fast-sort";
4+
5+
let work = ['2024_4', '2025_1']
6+
7+
if(true) {
8+
work = []
9+
for(let year = 2012;year<=2024;year++) {
10+
for(let term = 1;term<=4;term++) {
11+
work.push(`${year}_${term}`)
12+
}
13+
}
14+
}
15+
16+
function parseTime(times) {
17+
return (times || '').split('\n').map(s => {
18+
s = s.trim();
19+
if (!s) return null;
20+
try {
21+
let date = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].indexOf(s.slice(0, 3));
22+
if (date === -1) date = ['월', '화', '수', '목', '금', '토', '일'].indexOf(s.slice(0, 1))
23+
const sh = s && +s.split(' ')[1].split(':')[0];
24+
const sm = s && +s.split(' ')[1].split(':')[1].split('~')[0];
25+
const eh = s && +s.split(' ')[1].split(':')[1].split('~')[1].split(':')[0];
26+
const em = s && +s.split(' ')[1].split(':')[2];
27+
return {date, sh, sm, eh, em}
28+
} catch (e) {
29+
return null;
30+
}
31+
}).filter(x => x)
32+
}
33+
34+
async function main(year = 2024, term = 4, file = `static/result_${year}_${term}.json`) {
35+
const raw = Object.values(await fetch('https://erp.kaist.ac.kr/sch/sles/SlesseCtr/findAllEstblSubjtList.do', {
36+
body: `_menuId=MTI0ODU1MjEwNTgwMTA3ODAwMDA%3D&_menuNm=%EC%A0%84%EC%B2%B4%EA%B0%9C%EC%84%A4%EA%B5%90%EA%B3%BC%EB%AA%A9%EC%A1%B0%ED%9A%8C&_pgmId=NzU0MzkyMTUwMjY%3D&%40d1%23syy=${year}&%40d1%23smtDivCd=${term}&%40d1%23deptCd=806&%40d1%23lwprtInclsYn=1&%40d1%23subjtCrseDivCd=&%40d1%23subjcDivCd=%2C13%2C32%2C12%2C75%2C30%2C31%2C76%2C73%2C74%2C10%2C70%2C71%2C11%2C77%2C34%2C72%2C35%2C36%2C37%2C38%2C39%2C40%2C41%2C42%2C43%2C33%2C78%2C96%2C95%2C93%2C94%2C92%2C90%2C91%2CZM%2CZN%2CZQ%2CZR%2CZW%2CZJ%2CZV%2CZZ%2CZL%2CZS%2CZY%2CZX%2CZO%2CZP%2CZT%2CZU%2CZK&%40d1%23subjtNm=&%40d1%23fromCdt=&%40d1%23toCdt=&%40d1%23englSubjtYn=&%40d1%23subjtCd=&%40d1%23chrgNm=&%40d1%23fromAtnlcPercpCnt=&%40d1%23toAtnlcPercpCnt=&%40d%23=%40d1%23&%40d1%23=dmCond&%40d1%23tp=dm&`,
37+
method: 'POST',
38+
headers: {
39+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
40+
}
41+
}).then(r => r.json()))[0]
42+
43+
console.log(raw)
44+
45+
const data = raw.map(r => {
46+
const dept = +r.deprtCd
47+
const type = r.subjcDivNm
48+
const code = r.subjtCd
49+
const old = r.subjtNo
50+
const title = r.subjtNm
51+
const group = (r.corseDvclsNo || '').trim() || null
52+
const prof = (r.chrgInstrNmLisup || '').split(',').map(p => p.trim())
53+
const where = r.lecrmNm
54+
const credit = r.cdt
55+
const kcode = r.osysCmptCd
56+
const au = r.actvtUnitHrs || 0
57+
const cap = r.atnlcPercpCnt || 0
58+
const reg = r.atnlcPcnt || 0
59+
const time = parseTime(r.lctreTm)
60+
const exam = parseTime(r.examTm)
61+
62+
return {dept, type, code, old, title, group, prof, where, time, exam, credit, kcode, au, cap, reg}
63+
}).filter(x => x)
64+
65+
try {
66+
const addl = `./static/add_${year}_${term}.json`
67+
const add = fs.readFileSync(addl)
68+
const addJson = JSON.parse(add)
69+
data.push(...addJson)
70+
} catch (e) {
71+
}
72+
73+
const deptMap = {"833": "수리과학과"};
74+
raw.forEach(r => deptMap[r.deprtCd] = r.deprtNm)
75+
76+
const res = {
77+
data, version: Date.now(), deptMap,
78+
}
79+
80+
writeFileSync(file, JSON.stringify(res))
81+
}
82+
83+
function other() {
84+
const fileNames = fs.readdirSync('static')
85+
const files = fileNames.filter(name => name.startsWith('result_')).map(name => {
86+
const li = name.split('_')
87+
return {year: +li[1], term: +li[2].split('.')[0], name}
88+
})
89+
const subjects = {}, titles = {}
90+
files.forEach(({year, term, name}) => {
91+
const data = fs.readFileSync(`static/${name}`)
92+
const json = JSON.parse(data)
93+
json.data.forEach(subject => {
94+
if (subject.code.includes('URP')) return
95+
if (!subjects[subject.code]) {
96+
subjects[subject.code] = ['', {}]
97+
titles[subject.code] = []
98+
}
99+
titles[subject.code].push(subject.title)
100+
101+
const key = ((year - 2000) * 10 + term) + ''
102+
if (!subjects[subject.code][1][key]) subjects[subject.code][1][key] = []
103+
subjects[subject.code][1][key].push([subject.group, subject.prof.length === 1 ? subject.prof[0] : subject.prof, subject.title])
104+
})
105+
})
106+
107+
const ignoreSets = ['졸업연구', '개별연구', 'URP', '논문연구'];
108+
for (const code in subjects) {
109+
const titleCnt = titles[code].reduce((obj, item) => {
110+
obj[item] = (obj[item] || 0) + 1
111+
return obj
112+
}, {})
113+
114+
const title = Object.keys(titleCnt).sort((a, b) => titleCnt[b] - titleCnt[a])[0]
115+
if (ignoreSets.some(ignore => title.includes(ignore))) {
116+
delete subjects[code]
117+
continue
118+
}
119+
subjects[code][0] = title
120+
121+
const li = []
122+
for (const key in subjects[code][1]) {
123+
for (const s of subjects[code][1][key]) {
124+
if (s[2] === title) s.pop()
125+
}
126+
li.push([+key, subjects[code][1][key]])
127+
}
128+
subjects[code][1] = sort(li).desc(['0'])
129+
}
130+
writeFileSync('static/other.json', JSON.stringify(subjects))
131+
}
132+
133+
Promise.all(work.map(w => {
134+
const li = w.split('_')
135+
return main(+li[0], +li[1], `static/result_${w}.json`)
136+
})).then(() => {
137+
other()
138+
console.log('done')
139+
})

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"scripts": {
66
"dev": "vite dev",
7-
"build": "node crawler.js && vite build",
7+
"build": "node crawler_new.js && vite build",
88
"preview": "vite preview",
99
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
1010
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"

src/routes/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
let data: any = {}, selected = [], hover, innerWidth, loaded = false, timeSegments = [], selTime, favorites = [],
1818
shared = null, detail = null;
1919
20-
$: filter = (li) => li.map(i => i.custom ? i : data.data.find(x => x.code === i.code && x.group === i.group)).filter(i => i);
20+
$: filter = (li) => li.map(i => i.custom ? i : data.data.find(x => (x.code === i.code || x.old === i.code) && x.group === i.group)).filter(i => i);
2121
$: {
2222
if ($page.url.hash?.length > 1 && data.data) {
2323
shared = JSON.parse(atob($page.url.hash.slice(1)))

static/other.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

static/result_2012_1.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

static/result_2012_2.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

static/result_2012_3.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

static/result_2012_4.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

static/result_2013_1.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

static/result_2013_2.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)