Last active
April 6, 2025 13:09
-
-
Save maxint137/bbd5b75e5ca66ea29f5bf277690c2eaf to your computer and use it in GitHub Desktop.
get the results from https://www3.zkai.co.jp/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Extract the pure data from https://www3.zkai.co.jp/ to render it graphically |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Test Scores Graph</title> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@latest"></script> | |
<style> | |
#myChart { | |
max-width: 1800px; | |
/* margin: 20px auto; */ | |
} | |
@media print { | |
.pagebreak { | |
page-break-before: always; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Absolute Scores</h1> | |
<canvas id="myChart"></canvas> | |
<div class="pagebreak"></div> | |
<h1>Relative Scores</h1> | |
<canvas id="myChart2"></canvas> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function fetchData() { | |
const response = await fetch("transformed_results.json"); | |
return await response.json(); | |
} | |
Chart.defaults.datasets.line.spanGaps = true; | |
const name_for_subject = (s) => { | |
switch (s) { | |
case "2": | |
case "3": | |
case "4": | |
return `Σ${s}`; | |
case "J": | |
return "Sociology"; | |
case "M": | |
return "Math"; | |
case "P": | |
return "Physics"; | |
case "L": | |
return "Japanese"; | |
default: | |
return s; | |
} | |
}; | |
function prepareChartData(data, useScore) { | |
const labels = []; | |
const subjects = Object.keys(data); | |
const datasets = subjects.map((subject) => ({ | |
label: name_for_subject(subject), | |
data: [], | |
borderColor: getRandomColor(), | |
backgroundColor: getRandomColor(0.2), | |
hidden: true, | |
})); | |
// Create an array to hold all results for sorting | |
const resultsArray = []; | |
subjects.forEach((subject) => { | |
data[subject].forEach((result) => { | |
const { monthTitle, score, ranking } = result; | |
const [numerator, denominator] = ranking.split("/").map(Number); | |
const rank = numerator / denominator; | |
// Extract year and month from monthTitle | |
const [year, grade, month, round] = monthTitle.match(/\d+/g); | |
// handle the 202X-01 glitch | |
const yearFixed = parseInt(year, 10) + ("1" == month ? 1 : 0); | |
// Push to results array for later sorting | |
resultsArray.push({ | |
monthTitle: `${yearFixed}-${month.padStart(2, "0")}${2 == round ? "b" : "a" | |
}`, | |
year: yearFixed, | |
month: parseInt(month, 10), | |
score: parseInt(score), // Convert score to a number | |
rank: rank, | |
subject, | |
}); | |
}); | |
}); | |
// Sort results array by year and month | |
resultsArray.sort((a, b) => a.monthTitle.localeCompare(b.monthTitle)); | |
// Fill datasets and labels based on sorted results | |
resultsArray.forEach(({ monthTitle, score, rank, subject }) => { | |
if (!labels.includes(monthTitle)) { | |
labels.push(monthTitle); | |
} | |
const datasetIndex = subjects.indexOf(subject); | |
const index = labels.indexOf(monthTitle); | |
datasets[datasetIndex].data[index] = Math.round(useScore ? score : (100 - rank * 100)); | |
datasets[datasetIndex].hidden = | |
datasets[datasetIndex].label.startsWith("Σ"); | |
}); | |
return { labels, datasets }; | |
} | |
function getRandomColor(alpha = 1) { | |
const randomColor = Math.floor(Math.random() * 16777215).toString(16); | |
return `rgba(${parseInt(randomColor.slice(0, 2), 16)}, ${parseInt( | |
randomColor.slice(2, 4), | |
16 | |
)}, ${parseInt(randomColor.slice(4, 6), 16)}, ${alpha})`; | |
} | |
async function renderChart() { | |
const data = await fetchData(); | |
const plugins = { | |
annotation: { | |
annotations: { | |
line: { | |
type: "line", | |
yMin: 85, // Set the Y value for the line | |
yMax: 95, // Same value to make it horizontal | |
borderColor: "orange", | |
borderWidth: 2, | |
label: { | |
content: "Target Level", | |
enabled: true, | |
position: "right", | |
}, | |
}, | |
}, | |
}, | |
}; | |
const options = { | |
responsive: true, | |
plugins, | |
scales: { | |
y: { | |
type: "logarithmic", | |
beginAtZero: false, | |
}, | |
}, | |
}; | |
new Chart(document.getElementById("myChart").getContext("2d"), { | |
type: "line", // Change to 'bar' for bar chart | |
data: prepareChartData(data, true), | |
options, | |
}); | |
new Chart(document.getElementById("myChart2").getContext("2d"), { | |
type: "line", // Change to 'bar' for bar chart | |
data: prepareChartData(data, false), | |
options, | |
}); | |
} | |
renderChart(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
id= | |
password= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import get from "axios"; | |
import { writeFileSync } from "fs"; | |
import dotenv from "dotenv"; | |
dotenv.config(); | |
let AUTH_TOKEN = ""; | |
const COOKIE = | |
"_gid=GA1.3.1769416064.1728788736; _gat_UA-2006405-8=1; _ga=GA1.1.1027775214.1728788736; _ga_81GV8D7XVC=GS1.1.1728818610.3.1.1728818635.0.0.0; _ga_QYD53YSE01=GS1.3.1728818611.3.1.1728818635.0.0.0"; | |
// API endpoints | |
const LIST_URL = | |
"https://prd-22eltab-lb-aws.zkai.co.jp/pa/monthlist?reportType=1&offset=0&limit=100"; | |
const TEST_RESULT_BASE_URL = | |
"https://prd-22eltab-lb-aws.zkai.co.jp/pa/monthlyTestResult"; | |
// Function to fetch the list of reports | |
async function fetchReportList() { | |
try { | |
const response = await get(LIST_URL, { | |
headers: { | |
authorization: AUTH_TOKEN, | |
cookie: COOKIE, | |
accept: "application/json, text/plain, */*", | |
"user-agent": | |
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57", | |
}, | |
}); | |
return response.data.reportList; | |
} catch (error) { | |
console.error("Error fetching report list:", error); | |
return []; | |
} | |
} | |
// Function to fetch test results based on report data | |
async function fetchTestResult(fiscalYear, month, times, grade, courseId) { | |
const url = `${TEST_RESULT_BASE_URL}?fiscalYear=${fiscalYear}&month=${month}×=${times}&grade=${grade}&courseId=${courseId}`; | |
console.log(url); | |
try { | |
const response = await get(url, { | |
headers: { | |
authorization: AUTH_TOKEN, | |
cookie: COOKIE, | |
accept: "application/json, text/plain, */*", | |
"user-agent": | |
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57", | |
}, | |
}); | |
return response.data; | |
} catch (error) { | |
console.error( | |
`Error fetching test result for fiscalYear: ${fiscalYear}, month: ${month}, times: ${times}, grade: ${grade}:`, | |
error.message | |
); | |
return null; | |
} | |
} | |
// Function to determine the course ID based on the grade | |
function determineCourseId(grade) { | |
return `A${grade}`; | |
} | |
// Main function to fetch all test results and save to a JSON file | |
async function fetchAllTestResults(token) { | |
AUTH_TOKEN = `Bearer ${token}`; | |
const reportList = await fetchReportList(); | |
const allTestResults = []; | |
for (const report of reportList) { | |
const { fiscalYear, grade, testCountPerMonth, attendedMonth } = report; | |
const courseId = determineCourseId(grade); | |
const testResult = await fetchTestResult( | |
fiscalYear, | |
attendedMonth, | |
testCountPerMonth, | |
grade, | |
courseId | |
); | |
if (testResult) { | |
allTestResults.push(testResult); | |
} | |
} | |
// Save the collected test results to a JSON file | |
writeFileSync( | |
"all_test_results.json", | |
JSON.stringify(allTestResults, null, 2) | |
); | |
console.log("All test results saved to all_test_results.json"); | |
return allTestResults; | |
} | |
function massageData(testResults) { | |
// Initialize the transformed data structure | |
const transformedData = {}; | |
// Process each test result | |
testResults.forEach((result) => { | |
const { monthlyTestResults } = result; | |
const { gradeDataResults } = monthlyTestResults; | |
gradeDataResults.forEach((subjectResult) => { | |
const { subjectCode, score, ranking, average, deviationValue } = | |
subjectResult; | |
// Create the subject entry if it doesn't exist | |
if (!transformedData[subjectCode]) { | |
transformedData[subjectCode] = []; | |
} | |
// Add the test result to the corresponding subject | |
transformedData[subjectCode].push({ | |
score, | |
ranking, | |
average, | |
deviationValue, | |
monthTitle: monthlyTestResults.title, // Including title for reference | |
}); | |
}); | |
}); | |
// Save the transformed data to a new JSON file | |
writeFileSync( | |
"transformed_results.json", | |
JSON.stringify(transformedData, null, 2) | |
); | |
console.log("Transformed data saved to transformed_results.json"); | |
} | |
fetch("https://prd-22eltab-lb-aws.zkai.co.jp/pa/authoricate", { | |
headers: { | |
accept: "application/json, text/plain, */*", | |
"accept-language": "en-US,en;q=0.9,ru;q=0.8", | |
"content-type": "application/json;charset=UTF-8", | |
Referer: "https://www3.zkai.co.jp/", | |
"Referrer-Policy": "strict-origin-when-cross-origin", | |
}, | |
body: `{"id":"${process.env.id}","password":"${process.env.password}"}`, | |
method: "POST", | |
}) | |
.then((response) => { | |
if (!response.ok) { | |
throw new Error("Network response was not ok"); | |
} | |
// Parsing the response as JSON | |
return response.json(); | |
}) | |
.then((data) => fetchAllTestResults(data.token)) | |
.then((res) => massageData(res)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment