Last active
December 3, 2020 23:54
-
-
Save vitaminac/b6790cb6c75a4f914430862896ab31d6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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": "" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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