Skip to content

Instantly share code, notes, and snippets.

@TheFlash2k
Created January 24, 2024 11:31
Show Gist options
  • Save TheFlash2k/91361979c8873b2a8263c81427f051ee to your computer and use it in GitHub Desktop.
Save TheFlash2k/91361979c8873b2a8263c81427f051ee to your computer and use it in GitHub Desktop.
Extract result of students of AU based on their roll numbers (Individual, Multiple and Range-based)
#!/usr/bin/env python3
import requests
from bs4 import BeautifulSoup
from urllib.parse import unquote
import argparse
import re
import json
from tabulate import tabulate
from pprint import pprint
def parse(content: str) -> dict:
details = {}
soup = BeautifulSoup(content, 'html.parser')
student_details = soup.find(attrs={'id':'AUContent_DataList1'})
attrs = [i.strip() for i in re.findall(r'<b>(.*?)</b>', str(student_details))]
if not attrs: return {}
details["rollnumber"], details["name"], details["class"] = attrs
course_details = soup.find(attrs={'id':'AUContent_GridView1'})
attrs = [
i.replace('</td>', '|').replace('<td>', '').strip().split('|')[:-1]
for i in re.findall(r'Black;">(.*?)\n', str(course_details))]
details["courses"] = {
i[0]: { # Course Name
"grade": i[1],
"credit-hours": i[2]
} for i in attrs
}
details["gpa"] = re.findall('>(.*?)<',str(soup.find(attrs={'id': 'AUContent_lbl_gpa'})))[0]
return details
def get_result(rollno: int) -> dict:
response = requests.post(
'https://portals.au.edu.pk/auresult/',
headers={
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'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',
}, data={
'ctl00$AUContent$ScriptManager1': 'ctl00$AUContent$searchupdatepanel|ctl00$AUContent$btnShow',
'ctl00$AUContent$txt_regid': str(rollno).replace(' ', ''),
'__VIEWSTATE': 'AfMz+9qUKSr/TJeFzIg4vhcdxHIN3WrjhvZwFsT46ISeCqURNZ2Fza3GJWfuC9X9shEfMkXdkEupKF6SF595wS5FQlr+49P4zitPGnTVNFfRykB2+cXm+k89PczTYJASIXGvCKWKsw+HBlDZZwn+MsGVFClDzCAat267sBRuMaLlq6X0TcQ4BM4uPbie0i7PPkSHdMNoZ/s/fRn3T4AuxAApxY+8aoeEdLreQS3FOVDCwxx26sCMSZjXUU7K0B+vx5k048BJcD+FzWDpSZL0XAItfjSSs1lzHBPh/6D/p7czJ3g06uK1YwidYK9rLOTVT5JuHJ3ZagHWJCDFDQOXyQzAN2E1GerX8xgxIT7sGk/Jvh8NeiGN441YnN9XVSQh',
'ctl00$AUContent$btnShow': 'Search Result',
})
return parse(content=response.text)
def run(rollno: str):
data = get_result(i)
if not data:
print(f"[!] Unable to extract result of {rollno}")
return
if args.output == "table":
table = [['Name:', data['name']],
['Roll Number:', data['rollnumber']],
['GPA:', data['gpa']],
['Class:', data['class']],
['', '', ''], # Empty row for separation
['Course', 'Credit Hours', 'Grade']]
for course, details in data['courses'].items():
table.append([course, details['credit-hours'], details['grade']])
tbl = tabulate(table, tablefmt='grid')
print(tbl)
else:
pprint(data)
if args.outfile:
try:
with open(args.outfile, "a") as f:
f.write(str(result).replace('"', '"') + '\n') # stupid json error
except:
print("[!] An error occurred while trying to access the file.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Extract results of AU student(s)")
parser.add_argument('-r', '--roll-number', help="Roll number(s) of the student you want to extract result of [Can be a comma seperated list]", type=lambda x: x.strip().split(','), dest="rollnos")
parser.add_argument('--range', help="Specify a range (inclusive) (Example: 190700-190764) to extract results of. Can also be (190700-190764-2) which will extract every 2nd roll number", dest="ranges")
parser.add_argument("-t", "--output-type", help="Specify the type of output you want.", choices=["json", "table"], default="table", dest='output')
parser.add_argument("-o", "--output-file", help="Specify the output file name (output stored in json format)", dest="outfile")
args = parser.parse_args()
if not args.rollnos and not args.ranges:
print("[!] Please specify either -r or --range")
exit(1)
if args.outfile:
print(f"[*] Storing output in {args.outfile}")
try: open(args.outfile, "w")
except:
print(f"[!] Unable to access {args.outfile}.")
args.outfile = None
if args.ranges:
try: ranges = [int(i) for i in args.ranges.split('-')]
except: ranges = []
if len(ranges) < 2 or len(ranges) > 3:
print('[!] Invalid range specified!')
exit(1)
begin = ranges[0]
end = ranges[1]
if(len(ranges) == 3): diff = ranges[2]
else: diff = 1
print(f"[*] Extracting result between {begin} and {end}")
for i in range(begin, end+1, diff):
run(i)
else:
print(f"[*] Extracting result(s) of {','.join(args.rollnos)}")
for i in args.rollnos:
run(i)
argparse
tabulate
beautifulsoup4
requests
@TheFlash2k
Copy link
Author

Usage:

You need to install the libraries:

pip3 install - r requirements.txt
  • If you want to only extract result of a single person:
python3 au-result.py -r roll_number
# Example:
python3 au-result.py -r 190792
  • If you want to extract results of multiple roll numbers:
python3 au-result.py -r roll_number1,roll_number2,roll_numberN # Comma seperated list
# Example:
python3 au-result.py -r 190792,190764,190794
  • If you want to extract results in a specific range:
python3 au-result.py --range begin-end-[diff]
# Example: Extract between 190700-190764:
python3 au-result.py --range 190700-190764

# Example2: Extract between 190700-190764, but every 2nd other roll number:
python3 au-result.py --range 190700-190764-2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment