import requests import pandas as pd import numpy as np from lxml import etree from typing import Union def get_responses(url: str) -> Union[str, pd.DataFrame]: r = requests.get(url) r.raise_for_status() tree = etree.HTML(r.content) name_raw: str = tree.xpath('//div[@class="main-info-pnl"]//td[.="Candidate Name"]/following-sibling::td/text()')[0] name = name_raw.split()[0].strip().lower() questions = [] for panel in tree.xpath('//div[@class="question-pnl"]'): qno_raw = panel.xpath('.//td[@class="bold" and starts-with(text(), "Q.")]/text()')[0].split()[-1] qno = int(qno_raw.split(".")[1].strip()) menu_tbl = panel.xpath('.//table[@class="menu-tbl"]')[0] qid = int(menu_tbl.xpath('.//td[.="Question ID :"]/following-sibling::td/text()')[0]) ono_raw = menu_tbl.xpath('.//td[.="Chosen Option :"]/following-sibling::td/text()')[0].strip() if ono_raw == "--": ono = None oid = None else: ono = float(ono_raw) oid = float(menu_tbl.xpath(f'.//td[.="Option {ono_raw} ID :"]/following-sibling::td/text()')[0].strip()) questions.append({ "QNO": qno, "QID": qid, "ONO": ono, "OID": oid, }) return name, pd.DataFrame(questions) def check_result(your_df: pd.DataFrame, master_df: pd.DataFrame) -> pd.DataFrame: df = pd.merge(your_df, master_df, how='left', on='QID') df['TOID'] = df['TOID'].astype(float) df['Score'] = np.where(df['OID'].isna(), 0, np.where(df['OID'] == df['TOID'], 4, -1)) print(f'Score: {df["Score"].sum()}') print(f'Correct: {len(df[df['Score'] == 4]['QNO'].tolist())}, Incorrect: {len(df[df['Score'] == -1]['QNO'].tolist())}, Unattempted: {len(df[df['Score'] == 0]['QNO'].tolist())}') print(df[df['Score'] == -1]['QNO'].tolist()) return df if __name__ == '__main__': response_url = '' master = pd.read_csv('master.csv') stdn_name, stdn = get_responses(response_url) stdn_df = check_result(stdn, master) stdn_df.to_csv(f'{stdn_name}-scorecard.csv', index=False)