Skip to content

Instantly share code, notes, and snippets.

@JeyyGit
Last active July 17, 2024 08:13
Show Gist options
  • Save JeyyGit/d639ea73020f2e9d466d5adeff823219 to your computer and use it in GitHub Desktop.
Save JeyyGit/d639ea73020f2e9d466d5adeff823219 to your computer and use it in GitHub Desktop.
Scraping Nilai dan Index iGracias + Komponen Nilai

Scraping Nilai dan Index iGracias + Komponen Nilai

Mengakses data tabel pada iGracias > Nilai > KHS > Lihat Nilai yang berisi data kode matkul, nama matkul, jumlah SKS, periode akademik, indeks, status aktif, dan status terakhir. Setiap mata kuliah, komponen penilaiannya di dapatkan dari API call lain dengan data nama komponen, persentase ke nilai akhir, dan nilai komponen.

Untuk mendapatkan data nilai setiap mata kuliah tanpa mengambil data dari API call komponennya, dapat mengatur kwarg session.get_grades(with_grade_components=False)

! Tidak ada data yang dibagikan ke pihak manapun, kecuali iGracias.

! Setiap melakukan login pada iGraciasSession akan tertera pada laman iGracias > Akun > Riwayat Login.

! I don't know if this is legal or not. So use it at your own risk 😉

from model import iGraciasSession
session = iGraciasSession(
username="USERNAME_IGRACIAS",
password="PASSWORD_IGRACIAS",
)
session.login()
grades = session.get_grades(with_grade_components=True)
for grade in grades:
print(f"id={grade.id} mata kuliah={grade.name} indeks={grade.index}")
total_comp_grade = 0
for grade_component in grade.grade_components:
total_comp_grade += grade_component.grade * grade_component.percentage * 0.01
print(
f"* komponen={grade_component.name} persentase={grade_component.percentage:g}% nilai={grade_component.grade:g}"
)
print(f"-- total nilai={round(total_comp_grade, 2):g}\n")
from __future__ import annotations
from typing import List, Literal, Optional, NamedTuple
import requests
import re
class GradeComponent(NamedTuple):
name: str
percentage: float
grade: float
@classmethod
def from_payload(cls, payload: dict) -> GradeComponent:
return cls(
name=payload["COMPONENTNAME"],
percentage=float(payload["PERCENTAGE"]),
grade=float(payload["TSCORE"]),
)
class Grade:
def __init__(
self,
id_: str,
code: str,
name: str,
sks: int,
academic_period: str,
index: Optional[
Literal[
"A", "A-", "AB", "B+", "B", "B-", "BC", "C+", "C", "C-", "D", "E", "T"
]
],
active_status: bool,
last_status: bool,
igracias_session: iGraciasSession,
grade_components: List[GradeComponent] | None = None,
) -> None:
self.id = id_
self.code = code
self.name = name
self.sks = sks
self.academic_period = academic_period
self.index = index
self.active_status = active_status
self.last_status = last_status
self.grade_components = grade_components
self.igracias_session = igracias_session
@classmethod
def from_payload(cls, payload: dict, igracias_session: iGraciasSession) -> Grade:
(
course_code,
course_name,
course_sks,
academic_period,
index,
active_status,
last_status,
course_id,
*_,
) = payload
sks = int(course_sks)
active_status = True if active_status.lower() == "y" else False
last_status = True if last_status.lower() == "y" else False
index = index if index else None
return cls(
id_=course_id,
code=course_code,
name=course_name,
sks=sks,
academic_period=academic_period,
index=index,
active_status=active_status,
last_status=last_status,
igracias_session=igracias_session,
)
def add_grade_components(self) -> None:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36(j)",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
}
payload = {"rId": self.id, "studentId": self.igracias_session.nim}
response = self.igracias_session.session.post(
"https://igracias.telkomuniversity.ac.id/libraries/ajax/ajax.score.php?act=getcomponentscore",
data=payload,
headers=headers,
)
self.grade_components = []
for grade_component_payload in response.json():
grade_component = GradeComponent.from_payload(grade_component_payload)
self.grade_components.append(grade_component)
def __repr__(self) -> str:
return f'<Grade {" ".join(f"{key}={val}" for key, val in self.__dict__.items() if key not in ["grade_components", "igracias_session"])}>'
class iGraciasSession:
def __init__(self, username: str, password: str) -> None:
self.username = username
self.password = password
self.session = requests.session()
self.nim = None
self.logged_in = False
def login(self) -> None:
payload = {
"textUsername": self.username,
"textPassword": self.password,
"submit": "Login",
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36(j)",
}
response = self.session.post(
"https://igracias.telkomuniversity.ac.id/index.php?pageid=2941",
data=payload,
headers=headers,
)
if (
not response.text
): # somehow succesful login gives status code 500 and unsuccessful ones gives status code 200
raise Exception("Error occured.")
response = self.session.post(
"https://igracias.telkomuniversity.ac.id/index.php?pageid=2941",
headers=headers,
)
pattern = re.compile(r"<title>\s*(\d+)\s*\|\s*Telkom University\s*</title>")
match_ = pattern.search(response.text)
self.nim = int(match_.group(1))
self.logged_in = True
def get_grades(self, with_grade_components: bool = True) -> List[Grade]:
if not self.logged_in:
raise Exception("You are not logged in.")
self.session.get("https://igracias.telkomuniversity.ac.id/score/?pageid=114")
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36(j)",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
}
response = self.session.get(
"https://igracias.telkomuniversity.ac.id/libraries/ajax/ajax.score.php?act=viewCompleteScoreStudent&iDisplayLength=100&studentId=1103202201=",
headers=headers,
)
grades: List[Grade] = []
for payload in response.json()["aaData"]:
grade = Grade.from_payload(payload, self)
grades.append(grade)
if with_grade_components:
for grade in grades:
grade.add_grade_components()
return grades
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment