-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJobFinder.js
More file actions
145 lines (126 loc) · 5.5 KB
/
Copy pathJobFinder.js
File metadata and controls
145 lines (126 loc) · 5.5 KB
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
import { promises as fs } from 'fs';
import fetch from 'node-fetch';
import * as cheerio from 'cheerio';
import getJobDetails from './JobDetails.js';
import CheckId from './Duplicate.js';
// Function to fetch with retry logic
export function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Function to fetch with retry logic and delay
async function fetchWithRetry(url, options, retries = 600, delayMs = 1000) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.text();
} catch (error) {
if (retries > 0) {
console.error('Fetch error:', error.message, `Retrying in ${delayMs / 1000} seconds...`);
await delay(delayMs);
return await fetchWithRetry(url, options, retries - 1, delayMs);
} else {
throw new Error('Max retries reached. Failed to fetch.');
}
}
}
// Main function to save job list
export default async function saveJobList(search, n) {
const keywords = search.replace(" ","%20");
const url = `https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search?keywords=${keywords}&start=${n}`;
const options = {
headers: {
accept: '*/*',
'accept-language': 'en-GB,en;q=0.9',
'csrf-token': 'ajax:2711472108347807678',
priority: 'u=1, i',
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
'sec-ch-ua-mobile': '?1',
'sec-ch-ua-platform': '"Android"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
//this code overrides login through the use of a previous cookie, cookie code should be replaced after expiry.
cookie:
'JSESSIONID=ajax:2711472108347807678; lang=v=2&lang=en-us; bcookie="v=2&90c31730-05c4-43c0-8a8b-d25a47589eff"; bscookie="v=1&202407050948080ccc55ea-5724-4e15-8f2d-136177637fb6AQHUVAXVZIRPYSNBtTI_whqUqKHIKUJl"; _gcl_au=1.1.1317281315.1720172892; lidc="b=VGST03:s=V:r=V:a=V:p=V:g=3247:u=1:x=1:i=1720172892:t=1720259292:v=2:sig=AQHhtRZS4R2cbyR_feDHTbaRZKQwknJv"; AMCVS_14215E3D5995C57C0A495C55%40AdobeOrg=1; AMCV_14215E3D5995C57C0A495C55%40AdobeOrg=-637568504%7CMCIDTS%7C19910%7CMCMID%7C54109288882820670884546633751466216722%7CMCAAMLH-1720777693%7C6%7CMCAAMB-1720777693%7C6G1ynYcLPuiQxYZrsz_pkqfLG9yMXBpb2zX5dvJdYQJzPXImdj0y%7CMCOPTOUT-1720180093s%7CNONE%7CvVersion%7C5.1.1; aam_uuid=54652106246005236114600370336310034137; _uetsid=b183c0303ab311efb46ea328c240870d; _uetvid=b183e4a03ab311efa706eb39b29a5861',
Referer: url,
'Referrer-Policy': 'strict-origin-when-cross-origin',
},
method: 'GET',
};
try {
// Fetch HTML content
const html = await fetchWithRetry(url, options);
// Load HTML content with cheerio
const $ = cheerio.load(html);
// Initialize an empty array for existing jobs
let existingJobList = [];
let existingJobIds=[];
try {
// Read existing job list from file
const existingData = await fs.readFile('./JSON/jobList.json', 'utf8');
const existingIdData = await fs.readFile('./JSON/jobIds.json', 'utf8');
// Check if the file is empty
if (existingData.trim() === '') {
console.log('./JSON/jobList.json is empty. No jobs to check.');
} else {
// Parse JSON data and ensure it's an array
try {
existingJobList = JSON.parse(existingData);
existingJobIds = JSON.parse(existingIdData)
if (!Array.isArray(existingJobList)) {
throw new Error('Parsed data is not an array');
}
} catch (jsonError) {
console.error('Error parsing ./JSON/jobList.json:', jsonError.message);
existingJobList = [];
}
}
} catch (error) {
// Handle file not found or JSON parsing errors
if (error.code === 'ENOENT') {
console.log('./JSON/jobList.json file does not exist. Creating new list.');
existingJobList = [];
} else {
console.error('Error reading ./JSON/jobList.json:', error.message);
existingJobList = [];
}
}
// Collect promises for job processing
const jobPromises = [];
$('li').each(async (index, element) => {
jobPromises.push(async () => {
// Extract job date
const job_paste_date = $(element).find('.job-search-card__listdate').attr('datetime');
// Extract job link
let href = $(element).find('a.base-card__full-link').attr('href');
if (href) {
// href = transformUrl(href);
const urlObj = new URL(href);
let urn = $(element).find('.base-card').attr('data-entity-urn');
urn = await urn.slice(18,-1)
console.log(urn);
if (!await CheckId(urn)) {
const job_details= await getJobDetails(urlObj)
existingJobIds.push({jobId:urn});
existingJobList.push({
jobId: urn,
link: href,
date: job_paste_date,
details: job_details
});
}
}
});
});
// Execute all job processing promises
await Promise.all(jobPromises.map(p => p()));
// Write the updated job list and Ids to the file
await fs.writeFile('./JSON/jobList.json', JSON.stringify(existingJobList, null, 2));
await fs.writeFile('./JSON/jobIds.json', JSON.stringify(existingJobIds, null, 2));
console.log('JSON file has been updated.', n);
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
}