123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- import numpy as np
- from bs4 import BeautifulSoup
- import psycopg2
- from selenium import webdriver
- from selenium.webdriver.chrome.service import Service
- from selenium.webdriver.chrome.options import Options
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.ui import WebDriverWait
- from selenium.webdriver.support import expected_conditions as EC
- import argparse
- import getpass
- try:
- # Configuración de Selenium
- options = Options()
- options.add_argument("--headless")
- options.add_argument("--disable-gpu")
- options.add_argument("--no-sandbox")
- options.add_argument("--disable-dev-shm-usage")
- options.add_argument("--window-size=1920x1080")
-
- PATH = "/usr/bin/chromedriver"
- service = Service(PATH)
- driver = webdriver.Chrome(service=service, options=options)
- except Exception as e:
- print(f"Error configurando el navegador: {e}")
- exit()
- try:
- # Parseo de argumentos
- parser = argparse.ArgumentParser()
- parser.add_argument("clave", help="Clave ULSA argument")
- args = parser.parse_args()
-
- clave = args.clave
- # Solicitar la contraseña de manera segura
- contraseña = getpass.getpass("Contraseña: ")
-
- if not clave or not contraseña:
- raise ValueError("Clave y/o contraseña no válidos")
- except Exception as e:
- print(f"Error en los argumentos: {e}")
- driver.quit()
- exit()
- try:
- # Navegar a la URL
- url = "sgu.ulsa.edu.mx/psulsa/alumnos/consultainformacionalumnos/consultainformacion.aspx"
- formatted_url = f"https://{clave}:{contraseña}@{url}"
- driver.get(formatted_url)
- driver.get(f'https://{url}')
- except Exception as e:
- print(f"Error navegando a la URL: {e}")
- driver.quit()
- exit()
- try:
- # If dentro del código existe un (case insensitive) Unauthorized
- if "Unauthorized" in driver.page_source:
- raise Exception("Credenciales inválidas")
- elemento = WebDriverWait(driver, 10).until(
- EC.presence_of_element_located((By.ID, "ctl00_contenedor_HistorialAlumno1_lblBtnSeccionHAcademico"))
- )
- elemento.click()
- except Exception as e:
- print(f"Error interactuando con la página: {e}")
- driver.quit()
- exit()
- try:
- # Procesamiento de HTML con BeautifulSoup
- html_doc = driver.page_source
- soup = BeautifulSoup(html_doc, 'lxml')
- table = soup.find('table', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_gvMaterias'})
-
- if table is None:
- raise Exception("Tabla no encontrada en la página")
-
- materias_sgu = []
- headers = [header.text for header in table.find_all('th')]
- def is_cell_empty(cell_content):
- return not cell_content.strip() or cell_content == u'\xa0'
- for row in table.find_all('tr'):
- cols = row.find_all('td')
- if cols and not any(is_cell_empty(col.text) for col in cols):
- materias_sgu.append({headers[i]: col.text for i, col in enumerate(cols)})
-
- for materia in materias_sgu:
- materia['SEMESTRE'] = materia.pop('\xa0')
- servicio_social = soup.find('span', attrs={'id': 'ctl00_contenedor_HistorialAlumno1_Header1_lblSS'}).text
- # puede ser Realizado, No Realizado
- if servicio_social == "No Realizado":
- Alumno_serviciosocial = False
- elif servicio_social == "Realizado":
- Alumno_serviciosocial = True
- except Exception as e:
- print(f"Error procesando HTML: {e}")
- exit()
- finally:
- driver.quit()
- # Conexión a la base de datos y operaciones
- conexion = psycopg2.connect(
- dbname="sgi",
- user="postgres",
- password="sys4lci",
- host="200.13.89.27",
- port="5432"
- )
- # Ejecutar la consulta para actualizar public."Alumno"."Alumno_serviciosocial"
- try:
- with conexion.cursor() as cursor:
- cursor.execute(f'UPDATE public."Alumno" SET "Alumno_serviciosocial" = {Alumno_serviciosocial} WHERE "Usuario_claveULSA" = \'{clave[2:]}\'')
- conexion.commit()
- except Exception as e:
- print(f"Error al actualizar el servicio social: {e}")
- if conexion:
- conexion.rollback()
-
- try:
- # Ejecutar la consulta para obtener los periodos
- with conexion.cursor() as cursor:
- cursor.execute('SELECT * FROM "Periodo"')
- Periodos = cursor.fetchall()
- except Exception as e:
- print(f"Error obteniendo los periodos de la base de datos: {e}")
- try:
- # Ejecutar la consulta para obtener los tipos de calificación
- with conexion.cursor() as cursor:
- cursor.execute('SELECT * FROM "TipoCalificacion"')
- TiposCalificacion = cursor.fetchall()
- except Exception as e:
- print(f"Error obteniendo los tipos de calificación de la base de datos: {e}")
- try:
- # Ejecutar la consulta para obtener las materias base
- with conexion.cursor() as cursor:
- cursor.execute('SELECT * FROM "Materia"')
- materias_base = cursor.fetchall()
- except Exception as e:
- print(f"Error obteniendo las materias de la base de datos: {e}")
- try:
- # Procesar y preparar las calificaciones para inserción/actualización
- calificaciones = []
- with conexion.cursor() as cursor:
- cursor.execute(f'''
- SELECT "Carrera_id", "PlanEstudio_id"
- FROM "Alumno_view"
- WHERE "Usuario_claveULSA" = {clave[2:]}
- ''')
- Alumno_base = cursor.fetchone()
- for materia_sgu in materias_sgu:
- materia_base = next((materia_base for materia_base in materias_base if (materia_sgu['Cve ULSA'] in materia_base[-1] or materia_sgu['Cve SEP'] in materia_base[-1]) and (Alumno_base[1] == materia_base[0])), None)
- if not materia_base:
- continue
- Periodo_base = next((Periodo_base for Periodo_base in Periodos if Periodo_base[-2] == materia_sgu['PERIODO']), None)
- if not Periodo_base:
- continue
- Calificacion_base = next((Calificacion_base for Calificacion_base in TiposCalificacion if Calificacion_base[-2] == materia_sgu['EXAMEN']), None)
- if not Calificacion_base:
- raise Exception(f"No se encontró el tipo de calificación {materia_sgu['EXAMEN']} en la base de datos")
-
- # buscar en la base de datos el grupo WHERE Grupo_desc = materia_sgu['GRUPO'] and if is not in the base insert it (note: semestre when printed in the console is '\xa0': '5')
- with conexion.cursor() as cursor:
- cursor.execute(f'''
- SELECT "Grupo_id"
- FROM "Grupo_view"
- WHERE REGEXP_REPLACE("Grupo_desc", '[^\d]', '', 'g') = '{materia_sgu["GRUPO"]}' AND (("Carrera_id" = {Alumno_base[0]}) OR "Carrera_esComun")
- ''')
- Grupo = cursor.fetchone()
- if Grupo:
- cursor.execute(f'''
- INSERT INTO public."Alumno_Materia"("Usuario_claveULSA", "Materia_id", "Periodo_id", "Grupo_id")
- VALUES ({clave[2:]}, {materia_base[0]}, {Periodo_base[0]}, {Grupo[0]})
- ON CONFLICT ("Usuario_claveULSA", "Materia_id", "Periodo_id") DO NOTHING
- ;
- ''')
- conexion.commit()
- if not materia_base or not Periodo_base or not Calificacion_base:
- print(f"No se encontraron coincidencias para la materia {materia_sgu['Cve ULSA']} o el periodo {materia_sgu['PERIODO']} o el tipo de calificación {materia_sgu['EXAMEN']}")
- continue # Saltar esta iteración si alguna coincidencia falla
- calificaciones.append(f"({clave[2:]}, {materia_base[0]}, {Periodo_base[0]}, {Calificacion_base[0]}, {materia_sgu['CALIF']}, CURRENT_DATE, 'SGU')")
-
- if not calificaciones or len(calificaciones) == 0:
- raise Exception("No hay calificaciones para insertar o actualizar.")
-
- # Inserción/actualización de calificaciones en la base de datos
- with conexion.cursor() as cursor:
- cursor.execute(f'''
- insert into "Alumno_Materia_Calificacion"
- ("Usuario_claveULSA", "Materia_id", "Periodo_id", "TipoCalificacion_id", "Calificacion_calif", "Calificacion_fecha", "Calificacion_comentario")
- values
- {','.join(calificaciones)}
- on conflict ("Usuario_claveULSA", "Materia_id", "Periodo_id", "TipoCalificacion_id")
- DO UPDATE SET "Calificacion_calif" = EXCLUDED."Calificacion_calif", "Calificacion_comentario" = EXCLUDED."Calificacion_comentario";
- ''')
- conexion.commit()
- except Exception as e:
- print(f"Error al insertar/actualizar las calificaciones: {e} Stack: {e.__traceback__}")
- # print the whole stack
- if conexion:
- conexion.rollback() # Revertir cambios en caso de error
- conexion.close()
|