Skip to content

Instantly share code, notes, and snippets.

@vitaminac
Last active December 3, 2020 23:54
Show Gist options
  • Save vitaminac/b6790cb6c75a4f914430862896ab31d6 to your computer and use it in GitHub Desktop.
Save vitaminac/b6790cb6c75a4f914430862896ab31d6 to your computer and use it in GitHub Desktop.
{
"username": "<login>",
"password": "<password>",
"proxy": false,
"salary": 0,
"periods": [
{
"StartTimeLaterThan": "1997/06/01",
"StartTimeBeforeThan": "2019/09/01",
"EndTimeLaterThan": "2018/08/01",
"EndTimeBeforeThan": "2050/03/01"
}
],
"keywords": [],
"filters": [],
"areas": ""
}
const fs = require("fs");
const cheerio = require("cheerio");
function readJSON(filename) {
return new Promise((resolve, reject) => {
fs.readFile(filename, "utf8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(JSON.parse(data));
}
});
});
}
function writeJSON(json, filename) {
return new Promise((resolve, reject) => {
fs.writeFile(filename, JSON.stringify(json), "utf8", (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
function formatDate(date) {
const [day, month, year] = date.match(/\d+/g);
return year + "/" + month.padStart(2, "0") + "/" + day.padStart(2, "0")
}
function parseNumber(str) {
const numbers = str.match(/\d+/);
if (numbers === undefined || numbers === null || numbers.length < 1) {
return 0;
} else {
return parseInt(numbers[0]);
}
}
async function updateAndNotify() {
const configurations = await readJSON("cfg.json");
const request = (function () {
const r = require("request").defaults({
baseUrl: "https://gestion2.urjc.es/",
proxy: configurations["proxy"],
jar: true
});
return (options) => {
return new Promise((resolve, reject) => {
r(options, (error, response, body) => {
if (error) {
reject(error);
} else {
resolve(body);
}
});
});
};
})();
async function apply(offer) {
await request({
method: "POST",
url: offer["link"],
form: {
protDatos: "on",
btnInscribir: ""
}
});
console.log("applying for");
console.log(offer);
}
async function parseOfferDetail(link, offer) {
const pattern = /Desde ([\d|/]+) hasta ([\d|/]+)/;
const doc = await request({
method: "GET",
url: link
});
const $ = cheerio.load(doc);
const trs = $("table").find("tr").toArray();
const period = $($(trs[0]).children("td")[1]).text().trim();
const group = pattern.exec(period);
const schedule = $($(trs[1]).children("td")[1]).text().trim();
const place = $($(trs[trs.length - 1]).children("td")[1]).text().trim();
try {
offer["start"] = formatDate(group[1]);
offer["end"] = formatDate(group[2]);
} catch (e) {
offer["period"] = period;
}
try {
offer["active"] = formatDate($($(".dato-oferta-inline").toArray()[0]).find("strong").text().trim());
} catch (e) {
offer["active"] = $($(".dato-oferta-inline").toArray()[0]).find("strong").text().trim();
}
offer["schedule"] = schedule;
offer["place"] = place;
offer["detail"] = $(".form-body").text().trim();
return offer;
}
async function getOffers() {
const existingOffers = await readJSON("offers.json");
let doc = await request({
method: "GET",
url: "/practicas/ofertas"
});
const $ = cheerio.load(doc);
const map = new Map();
$(".list-group-item").toArray().forEach((offer) => {
const link = $(offer).find(".enlace-oferta").find("form").attr("action");
const inscription = $(offer).find(".inscripciones").text().trim().match(/(\d+)/g);
map.set(link, {
link: link,
title: $(offer).find(".titulo-oferta").text().trim(),
weeklyhours: parseNumber($(offer).find(".oferta-sem").text().trim()),
totalhours: parseNumber($(offer).find(".oferta-tot").text().trim()),
salary: parseNumber($(offer).find(".rem").text().trim()),
close: $(offer).find(".cierre").text().trim(),
applicant: parseInt(inscription[0]),
accepted: parseInt(inscription[1]),
available: parseInt(inscription[2]) - parseInt(inscription[1]),
areas: $(offer).find(".area-inline").map((i, e) => $(e).text()).toArray().join(" ")
});
});
existingOffers.forEach((offer) => {
if (offer["detail"] !== undefined && offer["detail"] !== null && offer["detail"] !== "") {
map.delete(offer["link"]);
}
});
const promises = [];
map.forEach((offer) => {
promises.push(new Promise((resolve) => {
try {
parseOfferDetail(offer["link"], offer).then((detailedInfo) => {
resolve(detailedInfo);
}, (err) => {
console.log(err);
resolve(undefined);
});
} catch (e) {
console.log(e);
}
}));
});
const newOffers = (await Promise.all(promises)).filter((offer) => {
return offer !== undefined;
});
map.clear();
existingOffers.concat(newOffers).forEach((offer) => map.set(offer["link"], offer));
await writeJSON(Array.from(map.values()).filter((offer) => {
return offer["detail"] !== undefined && offer["detail"] !== null && offer["detail"] !== "";
}), "offers.json");
return newOffers;
}
async function login() {
await request({
method: "GET",
url: "/practicas/"
});
await request({
method: "POST",
url: "/practicas/login",
form: { username: configurations["username"], password: configurations["password"] }
});
}
async function logout() {
await request({
method: "GET",
url: "/practicas/desconectar"
});
}
function filter(offer) {
if (configurations["periods"].some((period =>
(offer["start"] > period["StartTimeLaterThan"]) &&
(offer["start"] < period["StartTimeBeforeThan"]) &&
(offer["end"] > period["EndTimeLaterThan"]) &&
(offer["end"] < period["EndTimeBeforeThan"])
))) {
if (offer["available"] <= 0) {
return false;
}
if (offer["salary"] && offer["salary"] < configurations["salary"]) {
return false;
}
if (configurations["areas"]) {
if (offer["areas"] && !offer["areas"].includes(configurations("areas"))) {
return false;
}
}
const content = offer["detail"].toLowerCase();
if (configurations["keywords"].length == 0) return true;
if (configurations["keywords"].some((keyword) => {
return content.includes(keyword.toLowerCase());
})) return true;
if (configurations["filteres"].length == 0) return true;
if (!configurations["filters"] || configurations["filters"].every((keyword) => {
return !content.includes(keyword.toLowerCase());
})) return true;
return false;
}
}
await login();
try {
// let newOffers = await getOffers();
newOffers = require("./offers.json");
newOffers = newOffers.filter(filter);
if (newOffers && newOffers.length > 0) {
const promises = newOffers.map(apply);
await Promise.all(promises);
}
} catch (e) {
console.log(e);
} finally {
await logout();
}
}
// setInterval((() => {
// updateAndNotify();
// return updateAndNotify;
// })(), 5 * 60 * 1000);
updateAndNotify();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment