From 86f39ea31cd203620f8cdf68026b5f5cd13d2f5f Mon Sep 17 00:00:00 2001 From: root Date: Tue, 10 Sep 2024 10:38:52 -0600 Subject: [PATCH 1/2] Revert "Borrado de archivos extra" This reverts commit 06feae543ad5c6f7e77ac1a72dba076e864a69dc. --- __pycache__/argument_parser.cpython-39.pyc | Bin 0 -> 664 bytes __pycache__/data_processing.cpython-39.pyc | Bin 0 -> 1832 bytes .../database_operations.cpython-39.pyc | Bin 0 -> 2132 bytes __pycache__/main.cpython-39.pyc | Bin 0 -> 3299 bytes __pycache__/selenium_setup.cpython-39.pyc | Bin 0 -> 826 bytes __pycache__/web_navigation.cpython-39.pyc | Bin 0 -> 1067 bytes extraccion_html.c | 194 ++++++++++++++++ .../argument_parser.cpython-36.pyc | Bin 0 -> 683 bytes .../argument_parser.cpython-39.pyc | Bin 0 -> 697 bytes .../data_processing.cpython-36.pyc | Bin 0 -> 2507 bytes .../data_processing.cpython-39.pyc | Bin 0 -> 2633 bytes .../database_operations.cpython-36.pyc | Bin 0 -> 2135 bytes .../database_operations.cpython-39.pyc | Bin 0 -> 2348 bytes lib/__pycache__/funciones.cpython-36.pyc | Bin 0 -> 6098 bytes lib/__pycache__/funciones.cpython-39.pyc | Bin 0 -> 6198 bytes lib/__pycache__/selenium_setup.cpython-36.pyc | Bin 0 -> 674 bytes lib/__pycache__/selenium_setup.cpython-39.pyc | Bin 0 -> 696 bytes lib/__pycache__/web_navigation.cpython-36.pyc | Bin 0 -> 2370 bytes lib/__pycache__/web_navigation.cpython-39.pyc | Bin 0 -> 2405 bytes lib/argument_parser.py | 17 ++ lib/data_processing.py | 53 +++++ lib/database_operations.py | 47 ++++ lib/funciones.py | 99 ++++++++ lib/log.py | 35 +++ lib/selenium_setup.py | 16 ++ lib/web_navigation.py | 54 +++++ logs.py | 16 ++ main.py | 105 +++++++++ proceso | Bin 0 -> 23224 bytes sgu.py | 217 ++++++++++++++++++ 30 files changed, 853 insertions(+) create mode 100644 __pycache__/argument_parser.cpython-39.pyc create mode 100644 __pycache__/data_processing.cpython-39.pyc create mode 100644 __pycache__/database_operations.cpython-39.pyc create mode 100644 __pycache__/main.cpython-39.pyc create mode 100644 __pycache__/selenium_setup.cpython-39.pyc create mode 100644 __pycache__/web_navigation.cpython-39.pyc create mode 100644 extraccion_html.c create mode 100644 lib/__pycache__/argument_parser.cpython-36.pyc create mode 100644 lib/__pycache__/argument_parser.cpython-39.pyc create mode 100644 lib/__pycache__/data_processing.cpython-36.pyc create mode 100644 lib/__pycache__/data_processing.cpython-39.pyc create mode 100644 lib/__pycache__/database_operations.cpython-36.pyc create mode 100644 lib/__pycache__/database_operations.cpython-39.pyc create mode 100644 lib/__pycache__/funciones.cpython-36.pyc create mode 100644 lib/__pycache__/funciones.cpython-39.pyc create mode 100644 lib/__pycache__/selenium_setup.cpython-36.pyc create mode 100644 lib/__pycache__/selenium_setup.cpython-39.pyc create mode 100644 lib/__pycache__/web_navigation.cpython-36.pyc create mode 100644 lib/__pycache__/web_navigation.cpython-39.pyc create mode 100644 lib/argument_parser.py create mode 100644 lib/data_processing.py create mode 100644 lib/database_operations.py create mode 100644 lib/funciones.py create mode 100644 lib/log.py create mode 100644 lib/selenium_setup.py create mode 100644 lib/web_navigation.py create mode 100644 logs.py create mode 100644 main.py create mode 100644 proceso create mode 100644 sgu.py diff --git a/__pycache__/argument_parser.cpython-39.pyc b/__pycache__/argument_parser.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b76b63ec29f1ff8c76f1b4cf8c92fcf7cc682af GIT binary patch literal 664 zcmYjOL2DC16n<}ZHrcKwqP-~eupV9kWA8 zfWQp;%ZhyzOavdG&jj|M!+%i+oDO_mMMxK~e?-T8q%=9PFvkTbN(TSml3XQMw~K5fl$ks_)>`RA=1Hc^T2`68q!YV{))c8W z(zOr&Eqvjjc6U=D&Q~T}TsL`awEqjPIh3|YjdAg-G%IDj!)+a34`g9SDtBR_N4a%e zUXN@ibd7pmJHA%WxHlrc2@?@m-A1GvAegnQhy)AX~aCF y1jsPLHb$(0F^lLP6KbR0rngR@eWQ+i@k*v8St_PPyPqypO8L?ARau67f-&bo`ggYdw5k-uRee8{eF*5Pqz_# zJHP+Rcbf?P<^~r(0)uzJ%$v|K#IQs|+{YL(!h&PeCoE(Q=mXYdE$BlQ^-y=}4_J-5 zxSD>C)53~DA$zLGQ|#Q6Zwh*McK~L7f#&dgi%PiRh>UQFcd)yGg#xq2S7by=!kPur z^OmsI5q^TV&?sOLn>t1%ISE*Mj6Xm}_{)0qj2k_gABANIbDc3BHOhuwFN2ftb2Pwg znq4`LEclN6t})=*UH5lhg*#{JJ9nC+X4z!VJ|?498I-L7d4PH-M3x-sqDU(3s13bz|*L%y=wm zoS%-jL`LI-nD1Lny-#EVrH3>Xr$1(~=92Hx%yNH7s)i~aQp>fV=2py&rA!$(OU8!l zJ&_6(8z2dn5|-gQA?BD$I^&wYd$}y+Dj5% z524AIXJE^pVCXQOtVy=*P|hz&l~QSz;m_I9ir8&14aP1#**!M|y9Q?7fJV3{-~1RD zIwHVUvV)JX3BN!ke%_D1@i6>L0l~B|Ny?>6_%OEzx&;Sx106wEVNnICl238fsv(*h zqf-Q+U?Qzi+<>v}K=Yp{&X-o9$!XSK`2U2i`k>xUKTWVn#0wNnvKbsf8xfxj+@Jn_QC61 z%(gEsufQB?5ZuPIB*GC1@pWeOQbswTyKnDyGa4@w+}l*UFlW!H)l5JQl60lEezIDHsZcQ!Lzue_NojB1Mt3}?${f?(oeYCBSducf2+A;nmFyr>2(2p+xa(+i=59l@c zQz9snFN`pQg1d)wSmF}^Hii)+OK3MNL9E^2@S(?dM+|e}$`jowpxA)S&3XNa)h3h= z!NBDTQ18Q!;+$#-MR7)^A)vG>&XsW$OX(V-eidHPk9sR>E4__-D*!dfRo*4~Mdxo# z*zqr*)ody`&611Uc^%dprz{jgit!BAPOf*mjef9c-tz4A3HCwpa~BRh4`CH84HYXS PUv{}S&fg)?T-5vrjo;p5 literal 0 HcmV?d00001 diff --git a/__pycache__/database_operations.cpython-39.pyc b/__pycache__/database_operations.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6816566916d0a97db194d3c21c10a550b2d03859 GIT binary patch literal 2132 zcmah~L2uhO6ecBEc3sC!*A+;MwIhrHt%t&K(iH20Zb-Ho=zzf(ngm7-3FDO0w%@2}WCwBE|Rk#P9o_=-gZx zLHq5`-}zrfg#OTj*;atT8eFOYh9QPM)J5zPE3(od?qYU8{hdXvquD)bh^ z8>l}28hlVYG1ZQnl!ihDJCduUs77kVbKEzT5G= z>Fhp-OLf6S*8{YRV-(}qh|L&w`Jpf_#DxypKo){$#%L3xv5iqg0+SiB{Q|u-4lqW6 zb$~GHpeKl#V|(BB%URz`}r*~yDw zl5+0n3O~X86_QtA_6=E-LIjIyCtQTrq59Q&V#p;8V4Z3VN6D4kuNR2kWQhr`Y5@$g z3~XUz^84E^+ISvUvAhb;9KCGPG^kS`e}+M{8KWa~jDBp6&DcD`3;=zB05HrV3T5AH7`u7Abh+`Z>-$DKZpn$n+jeY_OSU`bVP+)d! zO(*~>?QA8Gz#3co7LXwAQxaG}f?~9hg1GJkA@$sd67CTWbO4kX+yb7@UB?CJgyT|A z^B@FXc;Ubog!}*DM@EV0-qu$S*Ed^$cHeWIMr}QHsF97rA<4zdxuI-4yzzt*tqRFZ@m%wyOQg~jUI^Wa_@-j>$g>?7iYL@(|eC0Lm_>MN3 zS($lPyWI$fKpfsvLCClt*#l!Gz)H~EZT=b zw3f5zgRv1CM>xisFK`Ep=pX}%)r2>?Kmc=AW|;$wxt}v;4;TaNif#g9ps-9Bvjb6V zT{7_4+=n8O^(k9)c{8J4Rxft-NzzHRP@xBdA(fPfe!zV$^I`#PIirB&)q{9YPM|t! zXC_p}oOX0)3hn>KS|xQm!{IudO}Dho1LrCAyi>^5tsKv1A(x}`fm=xZQ`Psjr5H^0 zUxVmM6D7l}jPGQ4y$>@d@H(OT@8N0mXa+C*5Pe+*^=sTrjoY(%Q2G?HROu)1Iz#D) zGfFqkQ990*p7t}?t*6+1;e$v3F7Z}6!~yAVyAB1R`&^x`>vps>MaRwJ$i*22dQ_c? zwMwKeoVldB)ss7=Sad71lV?imy==2yuB_ShJpD|odDtXFr-VPmxt>V2vsRSU#aU`S yNez;;!9Y@J3DCt`YVAo4s3h9F)pUB73cK`RAXw<}Pcf`e`lC}a%9l&kQsrN!h6&{W literal 0 HcmV?d00001 diff --git a/__pycache__/main.cpython-39.pyc b/__pycache__/main.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b9a52853a0de16f8208fe5f9b784f3b32a4a31d GIT binary patch literal 3299 zcmb^zNo*U*vAbu69Nv;FS)#8DHpeaNkmSOenz`w<0UHsU17iiA%JE z5x04HjH$~BuZ;2iDzncbTI1+`{aJ%Id2Nip#^$6GwcOcPl;G^5IlE-|ALd5Bp`SMNWh3F& zx%rx*uNZn;%M`!QTkK35B`dFO1?pcWwkCv~1?|s0t!S;j5UK&UWGtC{WpZ|Gn?1zN zn|r7}A)>09c@?~V;Q@iwf@-mEjqxwAn$uLU59PHUfw19Y#5c8tEy}5Ji z&W$@;M#l~jx->u)nKBy7us8)o!ypzlwglj!Mot6xKj?LKFC3&BK@|4Ft_c;NaoP2| zpkz>#Hb1-e$>!D@3etIS&TDS1rD$t~w4-0^`2CrV)VaBHcl!>lZUjPb5x_OR!XLcU zAvGkIJX)RIeaL8a<|M#Ry`vZqosDa^Z+$#GeaYLnyR);owddcswzql7dw=)l-S<1k z;k)h$U1Epx-VeN)NUbQ)mo>fZY2p4mhQR(Az3+NAMK(y+J?a_+bS~_zG~utXN1G?T z#ih`RGW>8W_4b1!@1#gBJ!m6=7bf5$6$mf&g09NId&5AicIFFbAi_k6G6)bA4Qc@B zsn<-2~6vKuKa0a$jNFNHYZB@Q=!nicv4h054(JzpnlM$>HeGcb><4kr0h3ZbErE?fR|tVA)qBD!UHY} zOLt0JH$*y1S?NO>(xq#rS{+*`({307UrxhMg)t zgIC~R$BV=!3-~%&!4EMZ=YVq&y8wkwieYQ*EnV&HJG*-@D3oKa_ERRi`ct!?F1vbm z+ki*@4#4m;h3?~Lgu!$*f-%701aJ(k6lF+W)Ribh;_|0Zes>X!4|nWMMS?K-n--z=*-hxdmeZG%x1n)`Yi&ehS|j zSr0+}+H-$*Wx_3M9Owf2oYpHi4XuKr#dKnjK;=v>} zNQLQKaD5(6yeRNw3IkUNyJ; z1L>RT8@|)cga}{!(aRE#PZaHxg?4{o>pogokTvE8MIDIZJ9@{GN_1>vvG|^*>e5_b zK8d5(6;ZbsbA!5SBSJ_W*R45RvYOVMRVPidUSTB2Fq?aYAIxvw^7X=W)f_F3UxiBpzE{HiXn@*Duy{S9AC?JQggp+Sry+(A8j6Gs|WLAh<1xaX5Hl(15 z@s{N@2X23$g^?TQFa`#RdHIn*!3bpi#Nw@-eTFY|gSm;l0Rrdn8fPuoI~I4EuL~}E zaJu$c)^VJ<@Odb-&U%i+1MN>j;mj6k)^(g%I@*uj|AJgB9X*enRQoeg1y(`K z<;u}PCLSFxRD4mJNB?;i*zm^`|m^6UV-Y)q^?o6PuEjX-&&dr6~sx& z#5za@rn2x@$zD8t`Ak*sQ(8?wB@y32_0aR@&PYj_jPxuWX%UJzNTUlal5{a#T$VR? z%?b21!Ri`)7ZngnEYjHtWu!$8&~t#IZeaXuV0*1yTGR01&K&OltYO2`a7#};o%f$} hTlQ*V>N52h*VF-)E?W;H$vmg^vm{Uj)R}h1KhIWr6+a}R;s3{p+l#HHg#?8XQ?`L(qF(s5}^9-~{-b0CF z>(olzdfp%#;DKVS{gHE|b((E;yH|AUif)hA_LP#UmH5YE;3r(R{8r?*-o1If)oNR% zF%Y_J?41N6#mY)6Rbiq_^HUyziW5L!mo~3}lt!+i(h4H@)$c_p6o6>uXX4_!?==sl zihYfoFp7$AMBRp%tM#suQg^dK-u)~N`jAIB@bRopIxJUars!*l`z&O53xrTc?^BoF zrOWU*RIP$9z>d!cw%{6j0tP?>u$-Q;3Ds<3X!C~iWxU88PPsNEZ=jZ>pS4f8c>WB(G5&!2$Qhyk2XexUOTGr&R6>BV#qCO*JkRB(xj zXXS|wqmu3IcIR(SG_yzvsLDtYI5EO{P@ P7Zh9>@>rtqFvtB1oKOjs literal 0 HcmV?d00001 diff --git a/extraccion_html.c b/extraccion_html.c new file mode 100644 index 0000000..2dd81ad --- /dev/null +++ b/extraccion_html.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include + +// Define the alumno struct +struct alumno { + char apellido_paterno[100]; + char apellido_materno[100]; + char curp[20]; + char clave_carrera[2]; + char plan[2]; + char clave[6]; + char nombre[100]; + char correo[100]; + char estatus; + char telefono[11]; + int semestre; + char sexo; +}; + +// Function to check for PostgreSQL connection errors +void check_conn_status(PGconn *conn) { + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); + PQfinish(conn); + exit(EXIT_FAILURE); + } +} + +// Function to check for PostgreSQL query execution errors +void check_exec_status(PGresult *res, PGconn *conn) { + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Query failed: %s", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(EXIT_FAILURE); + } +} + +// Function to extract content from an HTML element by ID +char* get_element_content_by_id(htmlDocPtr doc, const char *id) { + xmlChar xpath[100]; + snprintf((char *)xpath, sizeof(xpath), "//*[@id='%s']", id); + + xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpath, xpathCtx); + + if (xpathObj == NULL || xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) { + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + return NULL; + } + + xmlNodePtr node = xpathObj->nodesetval->nodeTab[0]; + xmlChar *content = xmlNodeGetContent(node); + + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + + return (char *)content; +} + +// Function to parse HTML content using libxml2 and populate the alumno struct +void parse_html(const char *html, struct alumno *alum) { + htmlDocPtr doc = htmlReadMemory(html, strlen(html), NULL, NULL, HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); + if (doc == NULL) { + fprintf(stderr, "Failed to parse HTML\n"); + return; + } + + char *content; + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblApPatAlumnoHP"); + if (content) { + strncpy(alum->apellido_paterno, content, 100); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblApMatAlumnoHP"); + if (content) { + strncpy(alum->apellido_materno, content, 100); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblCURPAlumnoHP"); + if (content) { + strncpy(alum->curp, content, 20); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveCarrera"); + if (content) { + strncpy(alum->clave_carrera, content, 2); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblAlupla"); + if (content) { + strncpy(alum->plan, content, 4); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveUlsa"); + if (content) { + strncpy(alum->clave, content, 7); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblNombreAlumnoHP"); + if (content) { + strncpy(alum->nombre, content, 100); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblCorreoAlumnoHP"); + if (content) { + strncpy(alum->correo, content, 100); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblStat"); + if (content) { + alum->estatus = content[0]; + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblTelefonoAlumnoHP"); + if (content) { + strncpy(alum->telefono, content, 11); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblSem"); + if (content) { + alum->semestre = atoi(content); + xmlFree(content); + } + + content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblSexoAlumnoHP"); + if (content) { + alum->sexo = content[0]; + xmlFree(content); + } + + xmlFreeDoc(doc); +} + +int main() { + // PostgreSQL connection parameters + const char *conninfo = "dbname=sgi user=postgres password=h3rcul3s#$ hostaddr=200.13.89.8 port=5432"; + PGconn *conn = PQconnectdb(conninfo); + + // Check connection status + check_conn_status(conn); + + // Execute SQL query to retrieve HTML content + PGresult *res = PQexec(conn, "SELECT datos_html FROM public.alumno_extraccion WHERE error_message IS NULL"); + check_exec_status(res, conn); + + // Process each row + int rows = PQntuples(res); + for (int i = 0; i < rows; i++) { + char *html_content = PQgetvalue(res, i, 0); + // printf("HTML Content: %s\n", html_content); + + struct alumno alum; + memset(&alum, 0, sizeof(alum)); // Initialize the struct to zero + + parse_html(html_content, &alum); + + printf("Apellido Paterno: %s\n", alum.apellido_paterno); + printf("Apellido Materno: %s\n", alum.apellido_materno); + printf("CURP: %s\n", alum.curp); + printf("Clave Carrera: %s\n", alum.clave_carrera); + printf("Plan: %s\n", alum.plan); + printf("Clave: %s\n", alum.clave); + printf("Nombre: %s\n", alum.nombre); + printf("Correo: %s\n", alum.correo); + printf("Estatus: %c\n", alum.estatus); + printf("Telefono: %s\n", alum.telefono); + printf("Semestre: %d\n", alum.semestre); + printf("Sexo: %c\n", alum.sexo); + } + + // Clean up + PQclear(res); + PQfinish(conn); + + return 0; +} + diff --git a/lib/__pycache__/argument_parser.cpython-36.pyc b/lib/__pycache__/argument_parser.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60e067a91b528044d18852dc068408b19142c6b2 GIT binary patch literal 683 zcmYjO&x_MQ6rMLp+cdTnToD8h<7tV9?m_UdEaI|y5Tpo;d+24E?Tp>T*`&-&R=T7Y zqeuS;kAfcj8~R_&RSFno4pes*t<8U$BgS~c_nk3fD13BnvE$}EC0%?2%$VeSWo8# zyIy`%so+EQQeH?lDUf%=H9q8QpR0W~XIAD?vu8{!e@;_dm|@xX0!3~$H*)!lAF}fC zR&st&c=D#lwkryg#4bW>Gp>zvgX3G1Z+)s=j|*|WG4A4K$md3T<1RLqYimBH_R@7y zBT}^D0wr@7pK(>nS6Ua^b*9qJxG_oS+KqyC;a21C9TeKJ_MPZ^So!xrr56XA&F5>{ za5i^$w;r00Y5boz_Ynw0Fo1}*;R#|4Jw)vrNub*p^uU8JGz)fM4{I(ux++AeiCba+E2Egz5msqM zFXJhzSly8EjKXonWJ8iK>>;U}GXlr1Rk2$tn;#;0;}Y4rrJty4*KL{1=rpPr$SSfL zJMGY^SQWizs4PA4jiDCT>SpIC1pfBb=^+;|Dz8-GGV0?CrN;v%^dfxjB0(tk5mwWM z;n(w-&ZX$_=jvSXp~1Zy0eC3*uF$)D!ksD<@TXkPe~fZxY_IGD0#i5;R?UBkJzhTE zP)_4>JyYU7GRa{9{v~kI;7z53MtRl!hO0N3b}FT8jg%V;YqQulmki+J4ac85NVFyG8-e>+`OEuYjO*J`+1L4b zf34wcMbH~h{Jo8u7#6tg93AovG;$h=4Z literal 0 HcmV?d00001 diff --git a/lib/__pycache__/data_processing.cpython-36.pyc b/lib/__pycache__/data_processing.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff108fde4b3e1f5fc7dcf93be6ee5c2fc1e4d025 GIT binary patch literal 2507 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 XYqJOz`;uiMUb4Z~7T+Yn8$tCSuzQo{ literal 0 HcmV?d00001 diff --git a/lib/__pycache__/database_operations.cpython-36.pyc b/lib/__pycache__/database_operations.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1405d4fc2c2471e26f8444730363c6d3400feb3 GIT binary patch literal 2135 zcmcIl%~K;q6z}f&$Pf~~77@td_`G5>4yr`X96 z@;e!628=(1u093938y}(2srRB*q@m3A|z7 zt}?LFUePgYh3G_KbVIkV23aRi}lXOpgeCw+g7o2 z@F@z5r;BxD%s(Zk(&G{aM~i(J4#5v z>nQbID0!+s1>~t7g);7~)Iu8+MI9byH@LAQ|KWlSy9NraNOj#XYF5)6SQ7|0PK|9T z!J|eby#REAg>fk-Er1}$P~=gJqbPt#^TTsq7^GDEOyn%AUM~3F(c1vTK~Rk_64Hrb zhpI%~^xp79BMuu^TXZ<2=0FggQJu2k&tf{Ap%YZ%E0^MXXd3kEz-_`LCTHZl+@}d` z(U?Kl==p4)C9I_-1j7R(2+$t+f;=LJ5GFnxaab!c%%ur8%cI7z!Si@J3zV)v=z`y~w$@5E1aM3icy68`3j7N2q67Rnq0tFucCMj1%__~Kw$ttc|p?`xa%f{MOgW7 z7$8FPSxne4CbXpuismXBx8g!;B|VG6z<9J9;t{snkdOanb#WM~MrQq+qh{yP^){M4 z$^(cjOHgPYHdb01ltMFGNL-%QLF&rMy7XK86*S|V@U;ezQ}-Eg>j>`APT-sHX?%k^lL zugO)ldjEcJgx%Jw68Q|`eOIOSe#%$`Y3O#_sqJk)dTj619)D)Lj_)0NuH!3 zd(U3!v9f(hms7pAzq{L8EZfU}^Y?mn8Rp+FxxVwQSlY0cdXr0Kdue!UwlIeaL1=qm zoQxgrC|v&fIzh3Fu`BE|AQJKEg8R#F?4{ zr`L-&oSqt)ThijFz3T3=*1*VRG#c5Q&{-%7UHgQ}x9~PYBEx1mC$UJRi6TocOBP{V zpS=2PRK#g49W|g9B7=T;_ok# C-rg1f literal 0 HcmV?d00001 diff --git a/lib/__pycache__/database_operations.cpython-39.pyc b/lib/__pycache__/database_operations.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebaf97ea00c7570a87f7f193dbe4757f5cb62ba3 GIT binary patch literal 2348 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 Vwr+Y~(_EGbe51&W6+NK1**~Y8szd+) literal 0 HcmV?d00001 diff --git a/lib/__pycache__/selenium_setup.cpython-39.pyc b/lib/__pycache__/selenium_setup.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ad8b5b3c0e987e49ce596653cb62ceee3accafc GIT binary patch literal 696 zcmaJI=9lFBJ$<8j$BHJ77dXvL)s-xvU za3z1qEfNxcfr?o>$z8>)X7t|7cy^xcbUGa)Fnab|oDhV5Idb11hu(slIRuV4E>MXR zj2$KgDQQA`Obf5{6Cbe0{ck7sT3k@W^5PB^a!od%#TB^z{ zT;JY20M1Xr%_W2y-JmUM(GSe=E!^EBazONeyaVzb;=vZzq{TOQOKSSXYe|cE_?>KN zOJTdwc{65gDNpnJ`ubiM)SL9;N%(7(Gq`7c~jjXuZ zFe4lB`uOF^{Q7wQV%|K7t4hF-}pGY48{rfD|O4YH+ZCuDKHlh%fwB?l%wO!3t zU%N*ORehGZ)dF%u(akZBAs`&!@%|7GkMKjRA3***3X{>kec0&vp3V;6bvCG+?Zox# jC;#c&Y44Ty*YpzZ1@~WeqgSQkwh(VHFyrJ;FdXs^;8m|V literal 0 HcmV?d00001 diff --git a/lib/__pycache__/web_navigation.cpython-36.pyc b/lib/__pycache__/web_navigation.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a3649bb08634452d2a8ffb3b45f4f8bad1d3a6a GIT binary patch literal 2370 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 literal 0 HcmV?d00001 diff --git a/sgu.py b/sgu.py new file mode 100644 index 0000000..a9e91c8 --- /dev/null +++ b/sgu.py @@ -0,0 +1,217 @@ +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() From d7226498b8ff715d31c05b33bafe08144e90f307 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 10 Sep 2024 10:43:47 -0600 Subject: [PATCH 2/2] =?UTF-8?q?Borrado=20de=20archivos=20extra=20=C3=9Anic?= =?UTF-8?q?amente=20app.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/argument_parser.cpython-39.pyc | Bin 664 -> 0 bytes __pycache__/data_processing.cpython-39.pyc | Bin 1832 -> 0 bytes .../database_operations.cpython-39.pyc | Bin 2132 -> 0 bytes __pycache__/main.cpython-39.pyc | Bin 3299 -> 0 bytes __pycache__/selenium_setup.cpython-39.pyc | Bin 826 -> 0 bytes __pycache__/web_navigation.cpython-39.pyc | Bin 1067 -> 0 bytes extraccion_html.c | 194 ---------------- .../argument_parser.cpython-36.pyc | Bin 683 -> 0 bytes .../argument_parser.cpython-39.pyc | Bin 697 -> 0 bytes .../data_processing.cpython-36.pyc | Bin 2507 -> 0 bytes .../data_processing.cpython-39.pyc | Bin 2633 -> 0 bytes .../database_operations.cpython-36.pyc | Bin 2135 -> 0 bytes .../database_operations.cpython-39.pyc | Bin 2348 -> 0 bytes lib/__pycache__/funciones.cpython-36.pyc | Bin 6098 -> 0 bytes lib/__pycache__/funciones.cpython-39.pyc | Bin 6198 -> 0 bytes lib/__pycache__/selenium_setup.cpython-36.pyc | Bin 674 -> 0 bytes lib/__pycache__/selenium_setup.cpython-39.pyc | Bin 696 -> 0 bytes lib/__pycache__/web_navigation.cpython-36.pyc | Bin 2370 -> 0 bytes lib/__pycache__/web_navigation.cpython-39.pyc | Bin 2405 -> 0 bytes lib/argument_parser.py | 17 -- lib/data_processing.py | 53 ----- lib/database_operations.py | 47 ---- lib/funciones.py | 99 -------- lib/log.py | 35 --- lib/selenium_setup.py | 16 -- lib/web_navigation.py | 54 ----- logs.py | 16 -- main.py | 105 --------- proceso | Bin 23224 -> 0 bytes sgu.py | 217 ------------------ 30 files changed, 853 deletions(-) delete mode 100644 __pycache__/argument_parser.cpython-39.pyc delete mode 100644 __pycache__/data_processing.cpython-39.pyc delete mode 100644 __pycache__/database_operations.cpython-39.pyc delete mode 100644 __pycache__/main.cpython-39.pyc delete mode 100644 __pycache__/selenium_setup.cpython-39.pyc delete mode 100644 __pycache__/web_navigation.cpython-39.pyc delete mode 100644 extraccion_html.c delete mode 100644 lib/__pycache__/argument_parser.cpython-36.pyc delete mode 100644 lib/__pycache__/argument_parser.cpython-39.pyc delete mode 100644 lib/__pycache__/data_processing.cpython-36.pyc delete mode 100644 lib/__pycache__/data_processing.cpython-39.pyc delete mode 100644 lib/__pycache__/database_operations.cpython-36.pyc delete mode 100644 lib/__pycache__/database_operations.cpython-39.pyc delete mode 100644 lib/__pycache__/funciones.cpython-36.pyc delete mode 100644 lib/__pycache__/funciones.cpython-39.pyc delete mode 100644 lib/__pycache__/selenium_setup.cpython-36.pyc delete mode 100644 lib/__pycache__/selenium_setup.cpython-39.pyc delete mode 100644 lib/__pycache__/web_navigation.cpython-36.pyc delete mode 100644 lib/__pycache__/web_navigation.cpython-39.pyc delete mode 100644 lib/argument_parser.py delete mode 100644 lib/data_processing.py delete mode 100644 lib/database_operations.py delete mode 100644 lib/funciones.py delete mode 100644 lib/log.py delete mode 100644 lib/selenium_setup.py delete mode 100644 lib/web_navigation.py delete mode 100644 logs.py delete mode 100644 main.py delete mode 100644 proceso delete mode 100644 sgu.py diff --git a/__pycache__/argument_parser.cpython-39.pyc b/__pycache__/argument_parser.cpython-39.pyc deleted file mode 100644 index 9b76b63ec29f1ff8c76f1b4cf8c92fcf7cc682af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 664 zcmYjOL2DC16n<}ZHrcKwqP-~eupV9kWA8 zfWQp;%ZhyzOavdG&jj|M!+%i+oDO_mMMxK~e?-T8q%=9PFvkTbN(TSml3XQMw~K5fl$ks_)>`RA=1Hc^T2`68q!YV{))c8W z(zOr&Eqvjjc6U=D&Q~T}TsL`awEqjPIh3|YjdAg-G%IDj!)+a34`g9SDtBR_N4a%e zUXN@ibd7pmJHA%WxHlrc2@?@m-A1GvAegnQhy)AX~aCF y1jsPLHb$(0F^lLP6KbR0rngR@eWQ+i@k*v8St_PPyPqypO8L?ARau67f-&bo`ggYdw5k-uRee8{eF*5Pqz_# zJHP+Rcbf?P<^~r(0)uzJ%$v|K#IQs|+{YL(!h&PeCoE(Q=mXYdE$BlQ^-y=}4_J-5 zxSD>C)53~DA$zLGQ|#Q6Zwh*McK~L7f#&dgi%PiRh>UQFcd)yGg#xq2S7by=!kPur z^OmsI5q^TV&?sOLn>t1%ISE*Mj6Xm}_{)0qj2k_gABANIbDc3BHOhuwFN2ftb2Pwg znq4`LEclN6t})=*UH5lhg*#{JJ9nC+X4z!VJ|?498I-L7d4PH-M3x-sqDU(3s13bz|*L%y=wm zoS%-jL`LI-nD1Lny-#EVrH3>Xr$1(~=92Hx%yNH7s)i~aQp>fV=2py&rA!$(OU8!l zJ&_6(8z2dn5|-gQA?BD$I^&wYd$}y+Dj5% z524AIXJE^pVCXQOtVy=*P|hz&l~QSz;m_I9ir8&14aP1#**!M|y9Q?7fJV3{-~1RD zIwHVUvV)JX3BN!ke%_D1@i6>L0l~B|Ny?>6_%OEzx&;Sx106wEVNnICl238fsv(*h zqf-Q+U?Qzi+<>v}K=Yp{&X-o9$!XSK`2U2i`k>xUKTWVn#0wNnvKbsf8xfxj+@Jn_QC61 z%(gEsufQB?5ZuPIB*GC1@pWeOQbswTyKnDyGa4@w+}l*UFlW!H)l5JQl60lEezIDHsZcQ!Lzue_NojB1Mt3}?${f?(oeYCBSducf2+A;nmFyr>2(2p+xa(+i=59l@c zQz9snFN`pQg1d)wSmF}^Hii)+OK3MNL9E^2@S(?dM+|e}$`jowpxA)S&3XNa)h3h= z!NBDTQ18Q!;+$#-MR7)^A)vG>&XsW$OX(V-eidHPk9sR>E4__-D*!dfRo*4~Mdxo# z*zqr*)ody`&611Uc^%dprz{jgit!BAPOf*mjef9c-tz4A3HCwpa~BRh4`CH84HYXS PUv{}S&fg)?T-5vrjo;p5 diff --git a/__pycache__/database_operations.cpython-39.pyc b/__pycache__/database_operations.cpython-39.pyc deleted file mode 100644 index 6816566916d0a97db194d3c21c10a550b2d03859..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2132 zcmah~L2uhO6ecBEc3sC!*A+;MwIhrHt%t&K(iH20Zb-Ho=zzf(ngm7-3FDO0w%@2}WCwBE|Rk#P9o_=-gZx zLHq5`-}zrfg#OTj*;atT8eFOYh9QPM)J5zPE3(od?qYU8{hdXvquD)bh^ z8>l}28hlVYG1ZQnl!ihDJCduUs77kVbKEzT5G= z>Fhp-OLf6S*8{YRV-(}qh|L&w`Jpf_#DxypKo){$#%L3xv5iqg0+SiB{Q|u-4lqW6 zb$~GHpeKl#V|(BB%URz`}r*~yDw zl5+0n3O~X86_QtA_6=E-LIjIyCtQTrq59Q&V#p;8V4Z3VN6D4kuNR2kWQhr`Y5@$g z3~XUz^84E^+ISvUvAhb;9KCGPG^kS`e}+M{8KWa~jDBp6&DcD`3;=zB05HrV3T5AH7`u7Abh+`Z>-$DKZpn$n+jeY_OSU`bVP+)d! zO(*~>?QA8Gz#3co7LXwAQxaG}f?~9hg1GJkA@$sd67CTWbO4kX+yb7@UB?CJgyT|A z^B@FXc;Ubog!}*DM@EV0-qu$S*Ed^$cHeWIMr}QHsF97rA<4zdxuI-4yzzt*tqRFZ@m%wyOQg~jUI^Wa_@-j>$g>?7iYL@(|eC0Lm_>MN3 zS($lPyWI$fKpfsvLCClt*#l!Gz)H~EZT=b zw3f5zgRv1CM>xisFK`Ep=pX}%)r2>?Kmc=AW|;$wxt}v;4;TaNif#g9ps-9Bvjb6V zT{7_4+=n8O^(k9)c{8J4Rxft-NzzHRP@xBdA(fPfe!zV$^I`#PIirB&)q{9YPM|t! zXC_p}oOX0)3hn>KS|xQm!{IudO}Dho1LrCAyi>^5tsKv1A(x}`fm=xZQ`Psjr5H^0 zUxVmM6D7l}jPGQ4y$>@d@H(OT@8N0mXa+C*5Pe+*^=sTrjoY(%Q2G?HROu)1Iz#D) zGfFqkQ990*p7t}?t*6+1;e$v3F7Z}6!~yAVyAB1R`&^x`>vps>MaRwJ$i*22dQ_c? zwMwKeoVldB)ss7=Sad71lV?imy==2yuB_ShJpD|odDtXFr-VPmxt>V2vsRSU#aU`S yNez;;!9Y@J3DCt`YVAo4s3h9F)pUB73cK`RAXw<}Pcf`e`lC}a%9l&kQsrN!h6&{W diff --git a/__pycache__/main.cpython-39.pyc b/__pycache__/main.cpython-39.pyc deleted file mode 100644 index 4b9a52853a0de16f8208fe5f9b784f3b32a4a31d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3299 zcmb^zNo*U*vAbu69Nv;FS)#8DHpeaNkmSOenz`w<0UHsU17iiA%JE z5x04HjH$~BuZ;2iDzncbTI1+`{aJ%Id2Nip#^$6GwcOcPl;G^5IlE-|ALd5Bp`SMNWh3F& zx%rx*uNZn;%M`!QTkK35B`dFO1?pcWwkCv~1?|s0t!S;j5UK&UWGtC{WpZ|Gn?1zN zn|r7}A)>09c@?~V;Q@iwf@-mEjqxwAn$uLU59PHUfw19Y#5c8tEy}5Ji z&W$@;M#l~jx->u)nKBy7us8)o!ypzlwglj!Mot6xKj?LKFC3&BK@|4Ft_c;NaoP2| zpkz>#Hb1-e$>!D@3etIS&TDS1rD$t~w4-0^`2CrV)VaBHcl!>lZUjPb5x_OR!XLcU zAvGkIJX)RIeaL8a<|M#Ry`vZqosDa^Z+$#GeaYLnyR);owddcswzql7dw=)l-S<1k z;k)h$U1Epx-VeN)NUbQ)mo>fZY2p4mhQR(Az3+NAMK(y+J?a_+bS~_zG~utXN1G?T z#ih`RGW>8W_4b1!@1#gBJ!m6=7bf5$6$mf&g09NId&5AicIFFbAi_k6G6)bA4Qc@B zsn<-2~6vKuKa0a$jNFNHYZB@Q=!nicv4h054(JzpnlM$>HeGcb><4kr0h3ZbErE?fR|tVA)qBD!UHY} zOLt0JH$*y1S?NO>(xq#rS{+*`({307UrxhMg)t zgIC~R$BV=!3-~%&!4EMZ=YVq&y8wkwieYQ*EnV&HJG*-@D3oKa_ERRi`ct!?F1vbm z+ki*@4#4m;h3?~Lgu!$*f-%701aJ(k6lF+W)Ribh;_|0Zes>X!4|nWMMS?K-n--z=*-hxdmeZG%x1n)`Yi&ehS|j zSr0+}+H-$*Wx_3M9Owf2oYpHi4XuKr#dKnjK;=v>} zNQLQKaD5(6yeRNw3IkUNyJ; z1L>RT8@|)cga}{!(aRE#PZaHxg?4{o>pogokTvE8MIDIZJ9@{GN_1>vvG|^*>e5_b zK8d5(6;ZbsbA!5SBSJ_W*R45RvYOVMRVPidUSTB2Fq?aYAIxvw^7X=W)f_F3UxiBpzE{HiXn@*Duy{S9AC?JQggp+Sry+(A8j6Gs|WLAh<1xaX5Hl(15 z@s{N@2X23$g^?TQFa`#RdHIn*!3bpi#Nw@-eTFY|gSm;l0Rrdn8fPuoI~I4EuL~}E zaJu$c)^VJ<@Odb-&U%i+1MN>j;mj6k)^(g%I@*uj|AJgB9X*enRQoeg1y(`K z<;u}PCLSFxRD4mJNB?;i*zm^`|m^6UV-Y)q^?o6PuEjX-&&dr6~sx& z#5za@rn2x@$zD8t`Ak*sQ(8?wB@y32_0aR@&PYj_jPxuWX%UJzNTUlal5{a#T$VR? z%?b21!Ri`)7ZngnEYjHtWu!$8&~t#IZeaXuV0*1yTGR01&K&OltYO2`a7#};o%f$} hTlQ*V>N52h*VF-)E?W;H$vmg^vm{Uj)R}h1KhIWr6+a}R;s3{p+l#HHg#?8XQ?`L(qF(s5}^9-~{-b0CF z>(olzdfp%#;DKVS{gHE|b((E;yH|AUif)hA_LP#UmH5YE;3r(R{8r?*-o1If)oNR% zF%Y_J?41N6#mY)6Rbiq_^HUyziW5L!mo~3}lt!+i(h4H@)$c_p6o6>uXX4_!?==sl zihYfoFp7$AMBRp%tM#suQg^dK-u)~N`jAIB@bRopIxJUars!*l`z&O53xrTc?^BoF zrOWU*RIP$9z>d!cw%{6j0tP?>u$-Q;3Ds<3X!C~iWxU88PPsNEZ=jZ>pS4f8c>WB(G5&!2$Qhyk2XexUOTGr&R6>BV#qCO*JkRB(xj zXXS|wqmu3IcIR(SG_yzvsLDtYI5EO{P@ P7Zh9>@>rtqFvtB1oKOjs diff --git a/extraccion_html.c b/extraccion_html.c deleted file mode 100644 index 2dd81ad..0000000 --- a/extraccion_html.c +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include -#include -#include -#include -#include - -// Define the alumno struct -struct alumno { - char apellido_paterno[100]; - char apellido_materno[100]; - char curp[20]; - char clave_carrera[2]; - char plan[2]; - char clave[6]; - char nombre[100]; - char correo[100]; - char estatus; - char telefono[11]; - int semestre; - char sexo; -}; - -// Function to check for PostgreSQL connection errors -void check_conn_status(PGconn *conn) { - if (PQstatus(conn) != CONNECTION_OK) { - fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); - PQfinish(conn); - exit(EXIT_FAILURE); - } -} - -// Function to check for PostgreSQL query execution errors -void check_exec_status(PGresult *res, PGconn *conn) { - if (PQresultStatus(res) != PGRES_TUPLES_OK) { - fprintf(stderr, "Query failed: %s", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - exit(EXIT_FAILURE); - } -} - -// Function to extract content from an HTML element by ID -char* get_element_content_by_id(htmlDocPtr doc, const char *id) { - xmlChar xpath[100]; - snprintf((char *)xpath, sizeof(xpath), "//*[@id='%s']", id); - - xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpath, xpathCtx); - - if (xpathObj == NULL || xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) { - xmlXPathFreeObject(xpathObj); - xmlXPathFreeContext(xpathCtx); - return NULL; - } - - xmlNodePtr node = xpathObj->nodesetval->nodeTab[0]; - xmlChar *content = xmlNodeGetContent(node); - - xmlXPathFreeObject(xpathObj); - xmlXPathFreeContext(xpathCtx); - - return (char *)content; -} - -// Function to parse HTML content using libxml2 and populate the alumno struct -void parse_html(const char *html, struct alumno *alum) { - htmlDocPtr doc = htmlReadMemory(html, strlen(html), NULL, NULL, HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); - if (doc == NULL) { - fprintf(stderr, "Failed to parse HTML\n"); - return; - } - - char *content; - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblApPatAlumnoHP"); - if (content) { - strncpy(alum->apellido_paterno, content, 100); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblApMatAlumnoHP"); - if (content) { - strncpy(alum->apellido_materno, content, 100); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblCURPAlumnoHP"); - if (content) { - strncpy(alum->curp, content, 20); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveCarrera"); - if (content) { - strncpy(alum->clave_carrera, content, 2); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblAlupla"); - if (content) { - strncpy(alum->plan, content, 4); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblCveUlsa"); - if (content) { - strncpy(alum->clave, content, 7); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblNombreAlumnoHP"); - if (content) { - strncpy(alum->nombre, content, 100); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblCorreoAlumnoHP"); - if (content) { - strncpy(alum->correo, content, 100); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblStat"); - if (content) { - alum->estatus = content[0]; - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblTelefonoAlumnoHP"); - if (content) { - strncpy(alum->telefono, content, 11); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_Header1_lblSem"); - if (content) { - alum->semestre = atoi(content); - xmlFree(content); - } - - content = get_element_content_by_id(doc, "ctl00_contenedor_HistorialAlumno1_lblSexoAlumnoHP"); - if (content) { - alum->sexo = content[0]; - xmlFree(content); - } - - xmlFreeDoc(doc); -} - -int main() { - // PostgreSQL connection parameters - const char *conninfo = "dbname=sgi user=postgres password=h3rcul3s#$ hostaddr=200.13.89.8 port=5432"; - PGconn *conn = PQconnectdb(conninfo); - - // Check connection status - check_conn_status(conn); - - // Execute SQL query to retrieve HTML content - PGresult *res = PQexec(conn, "SELECT datos_html FROM public.alumno_extraccion WHERE error_message IS NULL"); - check_exec_status(res, conn); - - // Process each row - int rows = PQntuples(res); - for (int i = 0; i < rows; i++) { - char *html_content = PQgetvalue(res, i, 0); - // printf("HTML Content: %s\n", html_content); - - struct alumno alum; - memset(&alum, 0, sizeof(alum)); // Initialize the struct to zero - - parse_html(html_content, &alum); - - printf("Apellido Paterno: %s\n", alum.apellido_paterno); - printf("Apellido Materno: %s\n", alum.apellido_materno); - printf("CURP: %s\n", alum.curp); - printf("Clave Carrera: %s\n", alum.clave_carrera); - printf("Plan: %s\n", alum.plan); - printf("Clave: %s\n", alum.clave); - printf("Nombre: %s\n", alum.nombre); - printf("Correo: %s\n", alum.correo); - printf("Estatus: %c\n", alum.estatus); - printf("Telefono: %s\n", alum.telefono); - printf("Semestre: %d\n", alum.semestre); - printf("Sexo: %c\n", alum.sexo); - } - - // Clean up - PQclear(res); - PQfinish(conn); - - return 0; -} - diff --git a/lib/__pycache__/argument_parser.cpython-36.pyc b/lib/__pycache__/argument_parser.cpython-36.pyc deleted file mode 100644 index 60e067a91b528044d18852dc068408b19142c6b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 683 zcmYjO&x_MQ6rMLp+cdTnToD8h<7tV9?m_UdEaI|y5Tpo;d+24E?Tp>T*`&-&R=T7Y zqeuS;kAfcj8~R_&RSFno4pes*t<8U$BgS~c_nk3fD13BnvE$}EC0%?2%$VeSWo8# zyIy`%so+EQQeH?lDUf%=H9q8QpR0W~XIAD?vu8{!e@;_dm|@xX0!3~$H*)!lAF}fC zR&st&c=D#lwkryg#4bW>Gp>zvgX3G1Z+)s=j|*|WG4A4K$md3T<1RLqYimBH_R@7y zBT}^D0wr@7pK(>nS6Ua^b*9qJxG_oS+KqyC;a21C9TeKJ_MPZ^So!xrr56XA&F5>{ za5i^$w;r00Y5boz_Ynw0Fo1}*;R#|4Jw)vrNub*p^uU8JGz)fM4{I(ux++AeiCba+E2Egz5msqM zFXJhzSly8EjKXonWJ8iK>>;U}GXlr1Rk2$tn;#;0;}Y4rrJty4*KL{1=rpPr$SSfL zJMGY^SQWizs4PA4jiDCT>SpIC1pfBb=^+;|Dz8-GGV0?CrN;v%^dfxjB0(tk5mwWM z;n(w-&ZX$_=jvSXp~1Zy0eC3*uF$)D!ksD<@TXkPe~fZxY_IGD0#i5;R?UBkJzhTE zP)_4>JyYU7GRa{9{v~kI;7z53MtRl!hO0N3b}FT8jg%V;YqQulmki+J4ac85NVFyG8-e>+`OEuYjO*J`+1L4b zf34wcMbH~h{Jo8u7#6tg93AovG;$h=4Z diff --git a/lib/__pycache__/data_processing.cpython-36.pyc b/lib/__pycache__/data_processing.cpython-36.pyc deleted file mode 100644 index ff108fde4b3e1f5fc7dcf93be6ee5c2fc1e4d025..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2507 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 XYqJOz`;uiMUb4Z~7T+Yn8$tCSuzQo{ diff --git a/lib/__pycache__/database_operations.cpython-36.pyc b/lib/__pycache__/database_operations.cpython-36.pyc deleted file mode 100644 index c1405d4fc2c2471e26f8444730363c6d3400feb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2135 zcmcIl%~K;q6z}f&$Pf~~77@td_`G5>4yr`X96 z@;e!628=(1u093938y}(2srRB*q@m3A|z7 zt}?LFUePgYh3G_KbVIkV23aRi}lXOpgeCw+g7o2 z@F@z5r;BxD%s(Zk(&G{aM~i(J4#5v z>nQbID0!+s1>~t7g);7~)Iu8+MI9byH@LAQ|KWlSy9NraNOj#XYF5)6SQ7|0PK|9T z!J|eby#REAg>fk-Er1}$P~=gJqbPt#^TTsq7^GDEOyn%AUM~3F(c1vTK~Rk_64Hrb zhpI%~^xp79BMuu^TXZ<2=0FggQJu2k&tf{Ap%YZ%E0^MXXd3kEz-_`LCTHZl+@}d` z(U?Kl==p4)C9I_-1j7R(2+$t+f;=LJ5GFnxaab!c%%ur8%cI7z!Si@J3zV)v=z`y~w$@5E1aM3icy68`3j7N2q67Rnq0tFucCMj1%__~Kw$ttc|p?`xa%f{MOgW7 z7$8FPSxne4CbXpuismXBx8g!;B|VG6z<9J9;t{snkdOanb#WM~MrQq+qh{yP^){M4 z$^(cjOHgPYHdb01ltMFGNL-%QLF&rMy7XK86*S|V@U;ezQ}-Eg>j>`APT-sHX?%k^lL zugO)ldjEcJgx%Jw68Q|`eOIOSe#%$`Y3O#_sqJk)dTj619)D)Lj_)0NuH!3 zd(U3!v9f(hms7pAzq{L8EZfU}^Y?mn8Rp+FxxVwQSlY0cdXr0Kdue!UwlIeaL1=qm zoQxgrC|v&fIzh3Fu`BE|AQJKEg8R#F?4{ zr`L-&oSqt)ThijFz3T3=*1*VRG#c5Q&{-%7UHgQ}x9~PYBEx1mC$UJRi6TocOBP{V zpS=2PRK#g49W|g9B7=T;_ok# C-rg1f diff --git a/lib/__pycache__/database_operations.cpython-39.pyc b/lib/__pycache__/database_operations.cpython-39.pyc deleted file mode 100644 index ebaf97ea00c7570a87f7f193dbe4757f5cb62ba3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2348 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 Vwr+Y~(_EGbe51&W6+NK1**~Y8szd+) diff --git a/lib/__pycache__/selenium_setup.cpython-39.pyc b/lib/__pycache__/selenium_setup.cpython-39.pyc deleted file mode 100644 index 1ad8b5b3c0e987e49ce596653cb62ceee3accafc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696 zcmaJI=9lFBJ$<8j$BHJ77dXvL)s-xvU za3z1qEfNxcfr?o>$z8>)X7t|7cy^xcbUGa)Fnab|oDhV5Idb11hu(slIRuV4E>MXR zj2$KgDQQA`Obf5{6Cbe0{ck7sT3k@W^5PB^a!od%#TB^z{ zT;JY20M1Xr%_W2y-JmUM(GSe=E!^EBazONeyaVzb;=vZzq{TOQOKSSXYe|cE_?>KN zOJTdwc{65gDNpnJ`ubiM)SL9;N%(7(Gq`7c~jjXuZ zFe4lB`uOF^{Q7wQV%|K7t4hF-}pGY48{rfD|O4YH+ZCuDKHlh%fwB?l%wO!3t zU%N*ORehGZ)dF%u(akZBAs`&!@%|7GkMKjRA3***3X{>kec0&vp3V;6bvCG+?Zox# jC;#c&Y44Ty*YpzZ1@~WeqgSQkwh(VHFyrJ;FdXs^;8m|V diff --git a/lib/__pycache__/web_navigation.cpython-36.pyc b/lib/__pycache__/web_navigation.cpython-36.pyc deleted file mode 100644 index 9a3649bb08634452d2a8ffb3b45f4f8bad1d3a6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2370 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 diff --git a/sgu.py b/sgu.py deleted file mode 100644 index a9e91c8..0000000 --- a/sgu.py +++ /dev/null @@ -1,217 +0,0 @@ -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()