diff --git a/.gitignore b/.gitignore index 2b9dbde..bd5c0e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.log -__pycache__/ \ No newline at end of file +__pycache__/ +env +*.Identifier \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2262cb5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Adil Mohammed K + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/PageLogin.py b/PageLogin.py index 14a07ff..1df9cbd 100644 --- a/PageLogin.py +++ b/PageLogin.py @@ -1,40 +1,45 @@ # Necessary imports from selenium import webdriver +from selenium.webdriver.chrome.service import Service as ChromeService +from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.keys import Keys from getpass import getpass import no_graph_features as ngf +import graph_features as gf from course_details import tabulate_course_details -from selenium.webdriver.firefox.options import Options +from selenium.webdriver.chrome.options import Options options = Options() options.headless = True # Specify Path to geckodriver for Firefox -driver = webdriver.Firefox(options=options, executable_path=r"./geckodriver-v0.26.0-linux64/geckodriver") +driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install())) # Navigating to the webpage driver.get("https://www.iitm.ac.in/viewgrades/") - # Loop prompting correct login details tried = False -while driver.current_url=="https://www.iitm.ac.in/viewgrades/index.html" or driver.current_url=="https://www.iitm.ac.in/viewgrades/": +while ( + driver.current_url == "https://www.iitm.ac.in/viewgrades/index.html" + or driver.current_url == "https://www.iitm.ac.in/viewgrades/" +): if tried == True: # Check if it is not the first iteration print("Incorrect Roll Number and/or Password") # Locate form fields - rollno = driver.find_element_by_name("rollno") - pwd = driver.find_element_by_name("pwd") + rollno = driver.find_element("name", "rollno") + pwd = driver.find_element("name", "pwd") roll = input("Enter your roll number:") password = getpass("Enter your password:") rollno.send_keys(roll) pwd.send_keys(password) - driver.find_element_by_name("submit").click() + driver.find_element("name", "submit").click() tried = True @@ -44,28 +49,38 @@ # Intro greeting -name = driver.find_element_by_xpath("/html/body/center/table/tbody/tr/th[3]") +name = driver.find_element("xpath", "/html/body/center/table/tbody/tr/th[3]") print("Hi,", name.text) -cg = driver.find_element_by_xpath("/html/body/center/center/table[1]/tbody/tr[last()]/td[last()]") +cg = driver.find_element( + "xpath", "/html/body/center/center/table[1]/tbody/tr[last()]/td[last()]" +) print("Your", cg.text) -courses, sem = tabulate_course_details(driver) +courses, sem, gpas = tabulate_course_details(driver) driver.close() -choice = ' ' -while choice.lower() != 'x': - choice = input('''\nHow do you want you visualize your grades: +choice = " " +while choice.lower() != "x": + choice = input( + """\nHow do you want you visualize your grades: a) GPA for courses taken in a specific department - - Other features will come soon. + b) Credits per stream in bar chart + c) GPA per semester in bar chart + d) Grade and credits in specific course Enter x to exit - ''') - if choice.lower() == 'a': + """ + ) + if choice.lower() == "a": dept, gpa = ngf.Dept_GPA(courses) print("Your GPA of the courses done in", dept, "department is", gpa, "\n") - dummy = input('''Press Enter to continue''') - - + dummy = input("""Press Enter to continue""") + elif choice.lower() == "b": + gf.Credits_stream(courses) + elif choice.lower() == "c": + gf.gpa_graph(gpas) + elif choice.lower() == "d": + course_check = input("Type course number to check: ") + ngf.courseCheck(course_check, courses) diff --git a/README.md b/README.md index 7481c52..4bf84ae 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,30 @@ -# viewgrades-scraper +# IITM Grades Scraper + An interactive and alternate Command Line visualisation of an IITM student's grades by scraping data from https://www.iitm.ac.in/viewgrades/ -Currently requires Firefox and works only on linux +Requires Chrome and can be run on Windows and Linux( also through WSL2) + ## Setup + 1. Clone the repository onto your system (or download the .zip file and unzip it) +
git clone https://github.com/Adil-MohammedK/IITM-viewgrades-scraper.git
2. Navigate to the location where you have cloned/downloaded the code on terminal -3. To install the neccesary packages - `pip install -r requirements.txt` -4. To run the code - `python PageLogin.py` +3. Create virtual environment +
python3 -m venv env
+4. Activate virtual environment +
source env/bin/activate
+5. To install the neccesary packages +
pip3 install -r requirements.txt
+6. To run the code +
python3 PageLogin.py
## Features currently available: + 1. Displays your CGPA 2. Accepts a department and give the GPA of the courses offered by that department - +3. Plot Credits per stream in bar chart +4. GPA per semester in bar chart +5. Find credits and grade for user input course + +# Contribution + +Some parts of this code is from [Murale127](https://github.com/murale127/viewgrades-scraper). I have changed the requirement from Firefox to Chrome and added few features from where he stopped. diff --git a/course_details.py b/course_details.py index abe91bb..6f552e0 100644 --- a/course_details.py +++ b/course_details.py @@ -1,13 +1,15 @@ def tabulate_course_details(driver): - ''' + """ driver: Webdriver element returns: Course and Semester details in a tabular format - ''' - courses = driver.find_element_by_xpath("/html/body/center/center/table[1]/tbody").text - course_list = courses.split('\n') + """ + courses = driver.find_element( + "xpath", "/html/body/center/center/table[1]/tbody" + ).text + course_list = courses.split("\n") - #print(course_list) + # print(course_list) course_list = [i.split() for i in course_list] @@ -18,26 +20,37 @@ def tabulate_course_details(driver): course_grade = [] credits = [] sem = [] + gpas = [] for i in course_list: if i[0].isnumeric(): course_code.append(i[1]) - course_name.append(' '.join(i[2:-4])) + course_name.append(" ".join(i[2:-4])) course_category.append(i[-4]) course_credits.append(i[-3]) course_grade.append(i[-2]) - count += 1 # Number of courses taken in a particular sem + count += 1 # Number of courses taken in a particular sem elif i[0] == "Earned": if i[1][-2:].isnumeric(): credits.append((int(i[1][-2:]), count)) + if i[2][0:3] == "GPA": + gpas.append(float(i[2][4:])) else: credits.append((int(i[1][-1]), count)) - + if i[2][0:3] == "GPA": + gpas.append(float(i[2][4:])) + else: count = 0 - sem.append(' '.join(i[:])) + sem.append(" ".join(i[:])) - course_summary = (course_code, course_name, course_category, course_credits, course_grade) + course_summary = ( + course_code, + course_name, + course_category, + course_credits, + course_grade, + ) sem_summary = (sem, credits) - return course_summary, sem_summary \ No newline at end of file + return course_summary, sem_summary, gpas diff --git a/geckodriver-v0.26.0-linux64/geckodriver b/geckodriver-v0.26.0-linux64/geckodriver deleted file mode 100755 index ff08a41..0000000 Binary files a/geckodriver-v0.26.0-linux64/geckodriver and /dev/null differ diff --git a/graph_features.py b/graph_features.py new file mode 100644 index 0000000..b7a6fa7 --- /dev/null +++ b/graph_features.py @@ -0,0 +1,59 @@ +import numpy as np +import pandas as pd +from pandas import Series, DataFrame +import matplotlib.pyplot as plt + + +def addlabels(x, y): + for i in range(len(x)): + plt.text(i, y[i], y[i], ha="center") + + +def Credits_stream(courses): + # plt.savefig("mygraph.png") + count_eng = 0 + count_pro = 0 + count_sci = 0 + count_hum = 0 + credit_eng = 0 + credit_pro = 0 + credit_sci = 0 + credit_hum = 0 + for i in range(len(courses[0])): + # print (courses[2][i]) + if courses[2][i] == "Engineering": + count_eng = count_eng + 1 + credit_eng = credit_eng + int(courses[3][i]) + elif courses[2][i] == "Professional": + count_pro = count_pro + 1 + credit_pro = credit_pro + int(courses[3][i]) + elif courses[2][i] == "Science": + count_sci = count_sci + 1 + credit_sci = credit_sci + int(courses[3][i]) + elif courses[2][i] == "Humanities": + count_hum = count_hum + 1 + credit_hum = credit_hum + int(courses[3][i]) + data = [credit_eng, credit_pro, credit_sci, credit_hum] + labels = ["Engineering", "Professional", "Science", "Humanities"] + addlabels(labels, data) + plt.xticks(range(len(data)), labels) + plt.xlabel("Category") + plt.ylabel("Credits") + plt.title("title") + plt.bar(range(len(data)), data) + plt.show() + + +def gpa_graph(gpas): + labels = [] + for i in range(len(gpas)): + # print(gpas[i]) + labels.append("Sem " + str(i)) + data = gpas + addlabels(labels, data) + plt.xticks(range(len(data)), labels) + plt.xlabel("Semester") + plt.ylabel("GPAs") + plt.title("title") + plt.bar(range(len(data)), data) + plt.show() diff --git a/no_graph_features.py b/no_graph_features.py index 65afcbc..8ad43aa 100644 --- a/no_graph_features.py +++ b/no_graph_features.py @@ -1,14 +1,25 @@ -grade2point = {"S":10, "A":9, "B":8, "C":7, "D":6, "E":4, "U":0, "I":0, "W":0} +grade2point = { + "S": 10, + "A": 9, + "B": 8, + "C": 7, + "D": 6, + "E": 4, + "U": 0, + "I": 0, + "W": 0, +} + def Dept_GPA(courses): - ''' + """ course: summary of the courses obtained from the webpage returns: GPA of the required department - ''' + """ while True: dept = input("Enter the department code: ") - total_credits = 0 + total_credits = 0 total_points = 0 for i in range(len(courses[0])): if courses[0][i][:2] == dept: @@ -17,6 +28,18 @@ def Dept_GPA(courses): total_credits += float(courses[3][i]) except: pass - gpa = round(total_points/total_credits, 2) + gpa = round(total_points / total_credits, 2) + + return dept, gpa + - return dept, gpa \ No newline at end of file +def courseCheck(name, courses): + flag = False + for i in range(len(courses[0])): + if courses[0][i] == name: + print("Course name is " + courses[1][i]) + print("Your grade in " + name + " is: " + courses[4][i]) + print("Your credits in " + name + " is: " + courses[3][i]) + flag = True + if flag == False: + print("No such course found") diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4f04a85 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[tool.black] +line-length = 85 +target-version = ['py39'] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 954f0db..2e26ca2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,5 @@ -selenium \ No newline at end of file +selenium +numpy +pandas +matplotlib +webdriver-manager \ No newline at end of file