From 1d5f0bcb5d7cd6d711391c1b2728401c5d79213c Mon Sep 17 00:00:00 2001 From: ION606 Date: Fri, 10 May 2024 13:27:48 -0700 Subject: [PATCH] fixed query params format --- .gitignore | 4 +++- classes/API.js | 30 ++++++++++++++++-------------- classes/Company.js | 10 +++++++--- tests/companyTests.js | 14 ++++++++++++++ 4 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 tests/companyTests.js diff --git a/.gitignore b/.gitignore index 7518461..ba8b951 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,6 @@ dist .yarn/install-state.gz .pnp.* -temp.js \ No newline at end of file +temp.js +config.json +cookie.txt diff --git a/classes/API.js b/classes/API.js index 6d2def1..cb595f2 100644 --- a/classes/API.js +++ b/classes/API.js @@ -46,7 +46,7 @@ function parseIncludedData(included, APIRef, excludeGeneric = false) { // APIRef may be ignored here return new EntityClass(item, APIRef); - }).filter(o => (excludeGeneric && o instanceof Company) || (!excludeGeneric && o)); + }).filter(o => (excludeGeneric && (o instanceof Company)) || (!excludeGeneric && o)); } @@ -58,7 +58,7 @@ export async function parseResponse(data, APIRef, excludeGeneric) { function findRangeIndex(number) { - const rangeMap = ["B", "C", "D", "E", "F", "G", "H", "I"] + const rangeMap = ["B", "C", "D", "E", "F", "G", "H", "I"]; const companySizeRanges = [ [1, 10], [11, 50], @@ -89,7 +89,7 @@ export function numsToSizes(...nums) { const ranges = nums.map(findRangeIndex); if (ranges.includes(-1)) throw `${nums} CONTAINS AN INVALID RANGE!`; - return `[${ranges.join("%2C")}]`; + return `[${ranges.join(",")}]`; } @@ -195,10 +195,14 @@ export default class linkedInAPIClass { * @param {boolean} [excludeGeneric=false] * @returns {Promise<[SocialActivityCounts | Group | Company | GenericEntity]>} */ - async searchCompanies(keyword, numEmp, start = 0, castToClass = true, excludeGeneric = false) { - let urlExt = `variables=(start:${start},origin:GLOBAL_SEARCH_HEADER,query:(keywords:${keyword},flagshipSearchIntent:SEARCH_SRP,queryParameters:List((key:resultType,value:List(COMPANIES))),includeFiltersInResponse:false))`; - if (numEmp) urlExt += `&companySize=${numsToSizes(...numEmp)}`; + async searchCompanies(keyword, numEmp = undefined, start = 0, castToClass = true, excludeGeneric = false) { + let urlExt = `variables=(start:${start},origin:GLOBAL_SEARCH_HEADER,query:(keywords:${keyword},flagshipSearchIntent:SEARCH_SRP,queryParameters:List((key:resultType,value:List(COMPANIES))${(numEmp) ? `(key:companySize,value:List(${numsToSizes(...numEmp)}))` : ''}),includeFiltersInResponse:false))`; const r = await this._makeReq(urlExt); + + if (!r?.included && r?.data?.errors) { + console.error(JSON.stringify(r.data.errors)) + throw "ERROR!"; + } if (!castToClass) return r; else return parseResponse(r, this, excludeGeneric); } @@ -207,7 +211,7 @@ export default class linkedInAPIClass { /** * @returns {Promise} * @param {String} keyword the user to search for - * @param {Number?} [limit=1000] + * @param {Number?} [limit=1000] the function will find the bound the given number is contained in (see {@link findRangeIndex} for ranges) * @param {boolean?} [castToClass=true] whether the function should return a list of Company classes or just raw JSON * @param {Array?} currentCompanies * @param {Array<1 | 2 | 3>?} conDeg the level(s) of connection to include (defults to all) @@ -219,16 +223,14 @@ export default class linkedInAPIClass { const empAll = []; for (let i = 0; i < limit; i += 50) { if (empAll.length >= limit) break; - let urlExt = `includeWebMetadata=true&variables=(start:${i},query:(keywords:${keyword},flagshipSearchIntent:SEARCH_SRP,queryParameters:List((key:resultType,value:List(PEOPLE)))))`; + let urlExt = `includeWebMetadata=true&variables=(start:${i},query:(keywords:${keyword},flagshipSearchIntent:SEARCH_SRP,queryParameters:List((key:resultType,value:List(PEOPLE))`; - if (currentCompanies.length) urlExt += `¤tCompany=["${currentCompanies.join('"%2C"')}"]`; - if (conDeg.length) { - const conFiltered = numToConDegs(conDeg); - if (conFiltered.length) urlExt += `network=["${currentCompanies.join('"%2C"')}"]}` - } + if (currentCompanies.length) urlExt += `,(key:currentCompany,value:List(${currentCompanies.join(',')}))`; + if (conDeg.length) urlExt += `,(key:network,value:List(${numToConDegs(conDeg)}))`; + urlExt += ')))'; const r = await this._makeReq(urlExt); - if (!r) return []; + if (!r?.included?.length) return []; const filtered = r.included.filter(e => e.template === 'UNIVERSAL'); diff --git a/classes/Company.js b/classes/Company.js index 3af2350..e6a0155 100644 --- a/classes/Company.js +++ b/classes/Company.js @@ -1,7 +1,8 @@ +import linkedInAPIClass from "../index.js"; import { LinkedInProfile } from "./Profile.js"; export class Company { - /** @type {import('../index.js').linkedInAPIClass} */ + /** @type {linkedInAPIClass} */ #APIRef; @@ -43,9 +44,11 @@ export class Company { /** * @returns {Promise} * @param {string} name - * @param {boolean} raw + * @param {boolean} raw + * @param {number} limit + * @note this function calls {@link linkedInAPIClass.searchEmployees} */ - searchEmployees = (name, limit=1000, raw=false) => this.#APIRef.searchEmployees(name, limit, !raw, [this.urn]); + searchEmployees = (name, limit = 1000, raw = false) => this.#APIRef.searchEmployees(name, limit, !raw, [this.entityNum]); async getInfo() { const toAdd = `q=universalName&universalName=${this.urn}`; @@ -64,6 +67,7 @@ export class Company { this.name = data.title.text; this.urn = data.entityUrn; this.url = data.navigationUrl; + this.entityNum = data.trackingUrn.replace('urn:li:company:', ''); if (!this.checkIfCompleted()) throw "NOT ALL NEEDED PARAMS FOUND!"; } diff --git a/tests/companyTests.js b/tests/companyTests.js new file mode 100644 index 0000000..d2fd504 --- /dev/null +++ b/tests/companyTests.js @@ -0,0 +1,14 @@ +import LinkedInAPIClass from "../index.js"; +import fs from 'fs'; + +(async () => { + const LAPI = new LinkedInAPIClass(); + + const o = JSON.parse(fs.readFileSync('config.json')); + await LAPI.login(o.email, o.password); + + const c = await LAPI.searchCompanies('microsoft', undefined, 0, true, true); + + const managers = await c.find(o => (o.name === 'Microsoft')).searchEmployees('manager', 5); + console.log(managers, managers.length); +})();undefined \ No newline at end of file