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'.")