import requests from bs4 import BeautifulSoup import concurrent.futures import re import logging import threading logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # Lock for thread-safe file operations write_lock = threading.Lock() # Global counter for numbering the results result_counter = 0 def get_result_data(roll): url = 'https://sresult.bise-ctg.gov.bd/s24/individual/result.php' data = {'roll': roll} try: res = requests.post(url, data) res.raise_for_status() except requests.RequestException as e: logging.error(f"Request failed for roll {roll}: {e}") return None sp = BeautifulSoup(res.text, 'html.parser') if sp.find('h2', string='SSC Result 2024') is None: logging.warning(f"No result found for roll {roll}") return None try: nums = sp.find_all('td', class_='cap_lt') marks = sp.find_all('td', class_='bg_grey') total = 0 gpa = '' group = '' school = '' subject_marks = [] for j, i in enumerate(nums): if re.search(r'GPA=\d+\.\d+', str(i)) is not None: gpa = re.search(r'GPA=(\d+\.\d+)', str(i)).group(1) if j == 3: group = i.text if i else '' if j == 8: school = i.text if i else '' name_elem = sp.find('td', width=True, class_='cap_lt') name = name_elem.text if name_elem else '' for mark in marks: mark_text = mark.text if mark else '' if re.search(r'\d{3}\(.+\)', mark_text) is not None: subject_marks.append(re.search(r'(\d{3})', mark_text).group(1)) total += int(re.search(r'(\d{3})', mark_text).group(1)) result_data = { 'roll': roll, 'name': name, 'total': total, 'gpa': gpa, 'group': group, 'school': school, 'subject_marks': subject_marks } return result_data except Exception as e: logging.error(f"Error parsing data for roll {roll}: {e}") return None def write_result_data(result_data): global result_counter with write_lock: result_counter += 1 with open("result_data.txt", "a") as f_main, open("subject_marks.txt", "a") as f_marks: main_result_str = f"{result_counter}\t{result_data['name']}\t{result_data['roll']}\t{result_data['gpa']}\t{result_data['total']}\t{result_data['school']}" f_main.write(main_result_str + '\n') marks_result_str = f"{result_data['roll']}\t" + "\t".join(result_data['subject_marks']) f_marks.write(marks_result_str + '\n') def process_rolls(rolls): results = [] for roll in rolls: result_data = get_result_data(str(roll)) if result_data: results.append(result_data) for result_data in results: write_result_data(result_data) def process_range(start, end, max_workers=50): logging.info(f"Processing range {start}-{end}...") rolls = list(range(start, end)) chunk_size = len(rolls) // max_workers with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: executor.map(process_rolls, [rolls[i:i + chunk_size] for i in range(0, len(rolls), chunk_size)]) logging.info(f"Range {start}-{end} complete") if __name__ == "__main__": start_range = int(input("starting roll: ")) end_range = int(input("Final roll: ")) max_worker = 50 step = max(1, (end_range - start_range) // max_worker) ranges = [(i, min(end_range, i + step)) for i in range(start_range, end_range, step)] for start, end in ranges: process_range(start, end, max_worker) logging.info("Processing complete. Results are written to 'result_data.txt' and 'subject_marks.txt'.")