UNPKG

rsshub

Version:
142 lines (139 loc) 4.65 kB
import dayjs from "dayjs"; import { load } from "cheerio"; //#region lib/routes/linkedin/models.ts var Job = class { constructor(title, link, company, location, pubDate, recruiter, description) { this.title = title; this.link = link; this.company = company; this.location = location; this.pubDate = pubDate; this.recruiter = recruiter; this.description = description; } }; //#endregion //#region lib/routes/linkedin/utils.ts /** * Constants */ const BASE_URL = "https://www.linkedin.com"; const KEYWORDS_QUERY_KEY = "keywords"; const JOB_TYPES_QUERY_KEY = "f_JT"; const JOB_TYPES = { F: "full-time", P: "part-time", C: "contract" }; const EXP_LEVELS_QUERY_KEY = "f_E"; const EXP_LEVELS = { 1: "internship", 2: "entry", 3: "associate", 4: "mid-senior", 5: "director" }; /** * Params parsing */ /** * Parse params in route into valid query params * e.g. /jobs/:keywords/:job_types/:exp_levels * if job_types is 'C-T' * the output search param is 'C,T', which can be * used as search param in query * @param {String} params params in route (separated by '-') * @param {Object} map valid value map for this param * @returns search params separated by ',' that can be used * as search param in url */ function parseParamsToSearchParams(params, map) { if (!params) return ""; return params.split("-").filter((v) => v in map).join(","); } /** * Parse params in route into human readable strings * e.g. /jobs/:keywords/:job_types/:exp_levels * if job_types is 'C-T' * the output is 'contract,full-time' * @param {String} params params in route (separated by '-') * @param {Object} map valid value map for this param * @returns param value strings separated by ',' */ function parseParamsToString(params, map) { if (!params) return ""; return params.split("-").filter((v) => v in map).map((v) => map[v]).join(","); } /** * HTML page parsing */ /** * Parse job search page * Example page: https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search?keywords=Software%20Engineer&location=United%20States&locationId=&geoId=103644278&sortBy=R&f_TPR=&position=1&pageNum=0 * * @param {String} data HTML string of job search page * @returns {Job[]} Array of jobs with data filled */ function parseJobSearch(data) { const $ = load(data); return $("li").toArray().map((elem) => { const elemHtml = $(elem); const link = elemHtml.find("a.base-card__full-link, a.base-card--link")?.attr("href")?.split("?")[0]; const title = elemHtml.find("h3.base-search-card__title")?.text()?.trim(); const company = elemHtml.find("h4.base-search-card__subtitle")?.text()?.trim(); const location = elemHtml.find("span.job-search-card__location")?.text()?.trim(); const pubDate = elemHtml.find("time")?.attr("datetime"); return new Job(title, link, company, location, pubDate); }); } const parseRouteParam = (searchParam) => { if (!searchParam || typeof searchParam !== "string") return "all"; return encodeURIComponent(searchParam.split(",").join("-")); }; /** * Parse company profile page for posts * Example page: https://www.linkedin.com/company/google/ * * @param {Cheerio} $ HTML string of company profile page * @returns {Array<JSON>} Array of company posts */ function parseCompanyPosts($) { return $("ul.updates__list > li").toArray().map((elem) => { const elemHtml = $(elem); return { link: elemHtml.find("a.main-feed-card__overlay-link").attr("href"), text: elemHtml.find("p.attributed-text-segment-list__content").text().trim(), date: parseRelativeShorthandDate(elemHtml.find("time").text().trim()) }; }); } /** * Parse company profile page for its name * Example page: https://www.linkedin.com/company/google/ * * @param {Cheerio} $ HTML string of company profile page * @returns {String} Company name */ function parseCompanyName($) { return $("h1.top-card-layout__title").text().trim(); } /** * Parse relative date shorthand string into a Date object * * @param {String} shorthand The shorthand string representing the date * @returns {Date|null} The parsed date or null if the format is invalid */ function parseRelativeShorthandDate(shorthand) { const match = shorthand.match(/^(\d+)([wdmyh])$/); if (!match) return null; const [, amount, unit] = match; return dayjs().subtract(Number.parseInt(amount), { w: "week", d: "day", m: "month", y: "year", h: "hour" }[unit]); } //#endregion export { JOB_TYPES_QUERY_KEY as a, parseCompanyPosts as c, parseParamsToString as d, parseRouteParam as f, JOB_TYPES as i, parseJobSearch as l, EXP_LEVELS as n, KEYWORDS_QUERY_KEY as o, EXP_LEVELS_QUERY_KEY as r, parseCompanyName as s, BASE_URL as t, parseParamsToSearchParams as u };