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