jobs-monorepo/services/scraper-hiringcafe/services/browserService.ts
Elshimy Ziad Magdy Taha a281363b61 hiring cafe scraper
2025-12-29 12:19:33 +05:00

99 lines
2.8 KiB
TypeScript

import { ElementHandle, Page } from "puppeteer-core";
import { randomDelay } from "../utils/browser";
import { Job } from "../types/job";
import { createDateFromRelativeTime } from "../utils/parse-time";
export class BrowserService {
private page: Page;
constructor(page: Page) {
this.page = page;
}
async getJobLinks(): Promise<string[]> {
const jobLinks = await this.page.evaluate(() => {
const links = document.querySelectorAll(
"a[href*='/viewjob/']"
) as NodeListOf<HTMLAnchorElement>;
return Array.from(links).map((link) => link.href);
});
return jobLinks;
}
async getJobData(jobLink: string): Promise<Job> {
let jobContainer: ElementHandle<Element> | null = null;
await this.page.goto(jobLink, {
waitUntil: "domcontentloaded",
timeout: 60000,
});
// await this.page.waitForNetworkIdle({ idleTime: 3000, timeout: 0 });
try {
jobContainer = await this.page.waitForSelector(
"::-p-xpath(/html/body/div[1]/div[3]/div/div/div/div[1])",
{
timeout: 10000,
}
);
} catch (error) {
console.log("No job listings found on the page");
return {} as Job;
}
if (jobContainer === null) {
console.log("Job container not found");
return {} as Job;
}
const jobTitle = await jobContainer.waitForSelector("h2");
const jobTitleText = await jobTitle?.evaluate((el) =>
el.textContent?.trim()
);
const company = await jobContainer.waitForSelector(
"span.text-xl.font-semibold.text-gray-700.flex-none"
);
const companyText = await company?.evaluate((el) => el.textContent?.trim());
const location = await jobContainer.waitForSelector(
"::-p-xpath(/html/body/div[1]/div[3]/div/div/div/div[1]/div/div[2]/div[3]/span)"
);
const locationText = await location?.evaluate((el) =>
el.textContent?.trim()
);
const jobPostTime = await jobContainer.waitForSelector(
"::-p-xpath(/html/body/div[1]/div[3]/div/div/div/div[1]/div/div[2]/div[1]/div/span)"
);
const jobPostTimeText = await jobPostTime?.evaluate((el) =>
el.textContent?.trim()
);
const time = jobPostTimeText?.split(" ")[1] ?? "";
const parsedDateTime = createDateFromRelativeTime(time);
const description = await this.page.waitForSelector("article");
const descriptionText = await description?.evaluate((el) =>
el.textContent?.trim()
);
const job: Job = {
company: companyText || "",
title: jobTitleText || "",
location: locationText || "",
description: descriptionText || "",
criteria: {},
jobLink,
companyLink: "",
provider: 7,
jobPostTime: parsedDateTime.toISOString(),
status: 0,
};
console.log({ job });
return job;
}
}