-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
223 lines (179 loc) · 6.11 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import type { ElementHandle, Page } from "puppeteer";
import puppeteer from "puppeteer-extra";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
puppeteer.use(StealthPlugin());
import { Dias, Horario, Materia } from "./libs/Materias";
import { MateriaParser } from "./libs/MateriaParser";
const readline = require("readline/promises");
require("dotenv").config();
type DATOS_MATERIA = "Grupo" | "Materia" | "Profesores" | "Horario";
const SELECTOR_GENERATOR = (i: number, dato: DATOS_MATERIA) => {
if (dato !== "Horario") {
return `#ctl00_mainCopy_GV_Horario_ctl0${i}_Lbl_${dato}`;
}
let ids = [];
for (let dia = 0; dia < 5; dia++) {
ids.push(`#ctl00_mainCopy_GV_Horario_ctl0${i}_Lbl_${Dias[dia]}`);
}
return ids;
};
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let form = async (page: Page) => {
// Pausa la automatización y permite que el usuario complete el inicio de sesión manualmente
await rl.question("\n|------>\n|SAES-1. Inicia sesión y luego presiona Enter aquí.");
};
let loginGoogle = async (page: Page) => {
await page.goto("https://accounts.google.com/Login", {
waitUntil: "networkidle2",
});
// Llena el campo de usuario
let nextButton = await page.$("#identifierNext button");
if (!nextButton) {
rl.question(
"\n|------>\nERROR EN AUTORRELLENO.\n\n|------>\n|SAES-1. Inicia sesion de forma manual. Presiona ENTER despues de haber iniciado sesion."
);
return;
}
await page.type("#identifierId", process.env.GOOGLE_EMAIL as string); // Lee BOLETA desde .env
await nextButton.click();
await new Promise((resolve) => setTimeout(resolve, 2000));
await page.waitForSelector("#password input", { visible: true });
await page.type("#password input", process.env.GOOGLE_PASSWORD as string); // Lee PASSWORD desde .env
await page.waitForSelector("#passwordNext button", { visible: true });
await page.click("#passwordNext button");
// Pausa la automatización y permite que el usuario complete el inicio de sesión manualmente
await rl.question(
"\n|------>\n|GOOGLE-3. Confirma la autenticación de doble factor y presiona ENTER para continuar."
);
};
if (
process.env.BOLETA &&
process.env.PASSWORD &&
process.env.GOOGLE_EMAIL &&
process.env.GOOGLE_PASSWORD
) {
console.log("Se encontraron las variables de entorno USERNAME y PASSWORD.");
form = async (page: Page) => {
// Llena el campo de usuario
await page.type(
"#ctl00_leftColumn_LoginUser_UserName",
process.env.BOLETA as string
); // Lee BOLETA desde .env
// Llena el campo de contraseña
await page.type(
"#ctl00_leftColumn_LoginUser_Password",
process.env.PASSWORD as string
); // Lee PASSWORD desde .env
// Pausa la automatización y permite que el usuario complete el inicio de sesión manualmente
await rl.question(
"\n|------>\n|SAES-1. Rellena el CAPTCHA manualmente y luego presiona Enter aquí."
);
};
}
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
// Navega a la página donde se requiere el inicio de sesión manual
await page.goto("https://www.saes.upiita.ipn.mx/");
await form(page);
await page.goto(
"https://www.saes.upiita.ipn.mx/Alumnos/Informacion_semestral/Horario_Alumno.aspx",
{ waitUntil: "networkidle2" }
);
const tableSelector = "#ctl00_mainCopy_GV_Horario";
const tableElement = await page.$(tableSelector);
let materias: Materia[] = [];
if (!tableElement) {
console.log("No se encontró la tabla.");
await browser.close();
process.exit(200);
}
// Extraer las materias de la tabla
let rows = await tableElement.$$("tr");
for (let i = 0; i < rows.length; i++) {
if (i == 0) {
continue;
}
let materia = await parseMateriaFromRow(rows[i], i + 1);
materias.push(materia);
}
// Iniciar sesion en Google Calendar
await loginGoogle(page);
// Crear eventos en Google Calendar
await page.goto("https://calendar.google.com/calendar/r", {
waitUntil: "networkidle2",
});
await rl.question(
"\n|------>\n|GOOGLE-5. Selecciona el calendario en el que quieres crear los eventos, unicamente debe estar activo el calendario en el que quieres poner tú horario. Presiona ENTER para continuar."
);
for (let i = 0; i < materias.length; i++) {
let materia = materias[i];
let eventos = MateriaParser.parseMateriaToEvento(materia);
for (let j = 0; j < eventos.length; j++) {
let evento = eventos[j];
console.log(evento.urlGenerador);
await page.goto(evento.urlGenerador);
await page.waitForSelector("#xSaveBu", { visible: true });
await page.click("#xSaveBu");
await page.waitForSelector("#gb", { visible: true });
await new Promise((resolve) => setTimeout(resolve, 1500));
}
}
// FINALIZAR
await rl.question("\n|------>\n|GOOGLE-7. Finaliza el proceso con ENTER.");
await browser.close();
process.exit(0);
})();
async function parseMateriaFromRow(
row: ElementHandle<HTMLTableRowElement>,
i: number
) {
let materia = new Materia();
const campos: DATOS_MATERIA[] = ["Grupo", "Materia", "Profesores", "Horario"];
for (const campo of campos) {
let selectorGenerado = SELECTOR_GENERATOR(i, campo);
if (selectorGenerado instanceof Array) {
let horarios: Horario[] = [];
for (let dia = 0; dia < selectorGenerado.length; dia++) {
let selectorDia = selectorGenerado[dia];
let campoDia = await row.$(selectorDia);
let value = await campoDia?.evaluate(
(campoDia) => campoDia.textContent
);
if (!value) {
continue;
}
horarios.push({
dia: dia,
horaInicio: value?.split(" - ")[0].trim(),
horaFin: value?.split(" - ")[1].trim(),
});
}
materia.horarios = horarios;
continue;
}
let campoElement = await row.$(selectorGenerado);
let value = await campoElement?.evaluate(
(campoElement) => campoElement.textContent
);
console.log(`Campo: ${campo} - Valor: ${value}`);
switch (campo) {
case "Grupo":
materia.grupo = value as string;
break;
case "Materia":
materia.nombre = value?.split(" - ")[1].trim() as string;
break;
case "Profesores":
materia.profesor = value?.trim() as string;
break;
}
}
console.log(materia);
return materia;
}