linkedin-api-voyager 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +232 -133
- package/lib/company.d.ts +1 -0
- package/lib/company.js +40 -0
- package/lib/config.d.ts +20 -0
- package/lib/config.js +94 -0
- package/{src/index.ts → lib/index.d.ts} +1 -1
- package/lib/index.js +22 -0
- package/lib/posts.d.ts +12 -0
- package/lib/posts.js +134 -0
- package/lib/search.d.ts +3 -0
- package/lib/search.js +184 -0
- package/lib/teste.d.ts +1 -0
- package/lib/teste.js +10 -0
- package/lib/types.d.ts +794 -0
- package/lib/types.js +2 -0
- package/lib/user.d.ts +38 -0
- package/lib/user.js +172 -0
- package/lib/utils.d.ts +45 -0
- package/lib/utils.js +606 -0
- package/package.json +11 -4
- package/src/account.ts +0 -116
- package/src/company.ts +0 -33
- package/src/config.ts +0 -109
- package/src/linkedin.ts +0 -0
- package/src/posts.ts +0 -71
- package/src/search.ts +0 -183
- package/src/utils.ts +0 -213
- package/tsconfig.json +0 -10
package/README.md
CHANGED
|
@@ -1,197 +1,296 @@
|
|
|
1
1
|
# LinkedIn API Voyager
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Biblioteca TypeScript para interagir com endpoints internos do LinkedIn (Voyager). Esta não é uma API oficial.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Instalação
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install linkedin-api-voyager
|
|
9
|
-
# ou
|
|
10
|
-
yarn add linkedin-api-voyager
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Autenticação (cookies)
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
Para fazer requisições autenticadas, você precisa dos cookies `li_at` e `JSESSIONID` da sua sessão no LinkedIn.
|
|
16
14
|
|
|
17
|
-
###
|
|
15
|
+
### Onde pegar `li_at` e `JSESSIONID`
|
|
16
|
+
|
|
17
|
+
1. Faça login no LinkedIn pelo navegador.
|
|
18
|
+
2. Abra o DevTools do navegador.
|
|
19
|
+
3. Vá em:
|
|
20
|
+
- Chrome/Edge: `Application` -> `Storage` -> `Cookies` -> `https://www.linkedin.com`
|
|
21
|
+
- Firefox: `Storage` -> `Cookies` -> `https://www.linkedin.com`
|
|
22
|
+
4. Copie os valores dos cookies:
|
|
23
|
+
- `li_at`: copie o valor inteiro.
|
|
24
|
+
- `JSESSIONID`: o valor costuma vir no formato `"ajax:123456789"`.
|
|
25
|
+
- Remova as aspas.
|
|
26
|
+
- Use apenas os números após `ajax:` (ex.: `123456789`).
|
|
27
|
+
|
|
28
|
+
### Salvando cookies em `linkedin_cookies.json`
|
|
29
|
+
|
|
30
|
+
Por padrão, a lib procura o arquivo `linkedin_cookies.json` na raiz do seu projeto.
|
|
31
|
+
|
|
32
|
+
Formato esperado:
|
|
18
33
|
|
|
19
34
|
```json
|
|
20
35
|
{
|
|
21
|
-
"JSESSIONID": "
|
|
22
|
-
"li_at": "
|
|
23
|
-
"timestamp":
|
|
36
|
+
"JSESSIONID": "123456789",
|
|
37
|
+
"li_at": "AQEDAR...",
|
|
38
|
+
"timestamp": 1730000000000
|
|
24
39
|
}
|
|
25
40
|
```
|
|
26
41
|
|
|
27
|
-
|
|
42
|
+
Observações:
|
|
28
43
|
|
|
29
|
-
|
|
44
|
+
- O arquivo `linkedin_cookies.json` já está no `.gitignore`.
|
|
45
|
+
- Não compartilhe esses cookies e não comite esse arquivo.
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
## Uso rápido
|
|
48
|
+
|
|
49
|
+
```ts
|
|
32
50
|
import {
|
|
33
|
-
|
|
51
|
+
getUserMiniProfile,
|
|
34
52
|
getProfissionalExperiences,
|
|
35
53
|
getCompany,
|
|
36
|
-
|
|
54
|
+
searchPeople,
|
|
55
|
+
getCommentsByPostUrl,
|
|
37
56
|
} from "linkedin-api-voyager";
|
|
57
|
+
|
|
58
|
+
const profile = await getUserMiniProfile("wesbush");
|
|
59
|
+
const experiences = await getProfissionalExperiences("wesbush");
|
|
60
|
+
const company = await getCompany("microsoft");
|
|
61
|
+
const people = await searchPeople("software engineer");
|
|
62
|
+
const comments = await getCommentsByPostUrl(
|
|
63
|
+
"https://www.linkedin.com/feed/update/urn:li:activity-1234567890/",
|
|
64
|
+
);
|
|
38
65
|
```
|
|
39
66
|
|
|
40
|
-
|
|
67
|
+
## API (por arquivo em `src/`)
|
|
68
|
+
|
|
69
|
+
O pacote reexporta os módulos listados em `src/index.ts`: `user`, `company`, `posts`, `search`, `utils`, `config`.
|
|
70
|
+
|
|
71
|
+
### `src/config.ts`
|
|
72
|
+
|
|
73
|
+
Constantes exportadas:
|
|
74
|
+
|
|
75
|
+
- `COOKIE_FILE_PATH`: caminho padrão do arquivo de cookies (`linkedin_cookies.json`).
|
|
76
|
+
- `API_BASE_URL`: base URL das chamadas Voyager (`https://www.linkedin.com/voyager/api`).
|
|
77
|
+
- `AUTH_BASE_URL`: base URL do LinkedIn (`https://www.linkedin.com`).
|
|
78
|
+
|
|
79
|
+
Funções exportadas:
|
|
80
|
+
|
|
81
|
+
- `saveCookies(JSESSIONID: string, li_at: string): Promise<void>`
|
|
82
|
+
- Salva os cookies no `COOKIE_FILE_PATH`.
|
|
83
|
+
- `loadCookies(): Promise<{ JSESSIONID: string; li_at: string; timestamp: number } | null>`
|
|
84
|
+
- Carrega e valida o arquivo de cookies.
|
|
85
|
+
- `Client(providedCookies?: { JSESSIONID: string; li_at: string }): Promise<AxiosInstance>`
|
|
86
|
+
- Cria um cliente HTTP com headers/cookies.
|
|
87
|
+
- Se existir `linkedin_cookies.json`, usa ele.
|
|
88
|
+
- Se não existir e `providedCookies` for passado, salva e usa.
|
|
89
|
+
- `fetchData(endpoint: string): Promise<any>`
|
|
90
|
+
- Faz um `GET` usando `Client()` e retorna `response.data`.
|
|
91
|
+
|
|
92
|
+
Exemplo (salvar cookies e criar cliente):
|
|
41
93
|
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
const profile = await getProfile("username-do-linkedin");
|
|
94
|
+
```ts
|
|
95
|
+
import { Client, saveCookies } from "linkedin-api-voyager";
|
|
45
96
|
|
|
46
|
-
|
|
47
|
-
const
|
|
97
|
+
await saveCookies("123456789", "AQEDAR...");
|
|
98
|
+
const api = await Client();
|
|
99
|
+
|
|
100
|
+
const me = await api.get("/me");
|
|
48
101
|
```
|
|
49
102
|
|
|
50
|
-
###
|
|
103
|
+
### `src/user.ts`
|
|
104
|
+
|
|
105
|
+
Tipos exportados:
|
|
106
|
+
|
|
107
|
+
- `MiniUserProfileLinkedin`
|
|
108
|
+
|
|
109
|
+
Funções exportadas:
|
|
110
|
+
|
|
111
|
+
- `getUserMiniProfile(identifier: string): Promise<MiniUserProfileLinkedin>`
|
|
112
|
+
- Busca dados básicos do perfil (nome, headline, imagens) e também o `about`.
|
|
113
|
+
- `identifier` é o `publicIdentifier` (parte final da URL `linkedin.com/in/<identifier>`).
|
|
114
|
+
|
|
115
|
+
- `extractProfileIdLinkedin(profileUrl: string): Promise<string | null>`
|
|
116
|
+
- Extrai o `publicIdentifier` de uma URL `linkedin.com/in/...`.
|
|
117
|
+
- Se você passar apenas o identificador, ele tenta usar diretamente.
|
|
118
|
+
- Retorna o ID numérico interno (sem o prefixo `urn:li:fsd_profile:`) quando encontra.
|
|
119
|
+
|
|
120
|
+
- `getProfileSectionAbout(identifier: string): Promise<string | null>`
|
|
121
|
+
- Retorna o texto de “Sobre” (about) do perfil.
|
|
122
|
+
|
|
123
|
+
- `getProfissionalExperiences(identifier: string): Promise<Array<any>>`
|
|
124
|
+
- Retorna a lista de experiências profissionais.
|
|
125
|
+
- Para cada experiência, tenta enriquecer com dados de empresa via `getCompany`.
|
|
126
|
+
|
|
127
|
+
- `getContactInfo(identifier: string): Promise<{ ... }>`
|
|
128
|
+
- Retorna informações de contato quando disponíveis (email, telefones, sites etc.).
|
|
129
|
+
|
|
130
|
+
- `getLinkedinSkills(identifier: string): Promise<Array<string | null>>`
|
|
131
|
+
- Retorna as skills (habilidades) listadas no perfil.
|
|
132
|
+
|
|
133
|
+
- `getLinkedinEducation(identifier: string): Promise<Array<any>>`
|
|
134
|
+
- Retorna a educação (escola, degree, datas, skills relacionadas quando houver).
|
|
135
|
+
|
|
136
|
+
- `getLinkedinCertifications(identifier: string): Promise<Array<any>>`
|
|
137
|
+
- Retorna certificações.
|
|
138
|
+
|
|
139
|
+
Exemplo:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import {
|
|
143
|
+
getUserMiniProfile,
|
|
144
|
+
getProfileSectionAbout,
|
|
145
|
+
getProfissionalExperiences,
|
|
146
|
+
getContactInfo,
|
|
147
|
+
getLinkedinSkills,
|
|
148
|
+
getLinkedinEducation,
|
|
149
|
+
getLinkedinCertifications,
|
|
150
|
+
} from "linkedin-api-voyager";
|
|
151
|
+
|
|
152
|
+
const identifier = "wesbush";
|
|
51
153
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
154
|
+
const mini = await getUserMiniProfile(identifier);
|
|
155
|
+
const about = await getProfileSectionAbout(identifier);
|
|
156
|
+
const experiences = await getProfissionalExperiences(identifier);
|
|
157
|
+
const contact = await getContactInfo(identifier);
|
|
158
|
+
const skills = await getLinkedinSkills(identifier);
|
|
159
|
+
const education = await getLinkedinEducation(identifier);
|
|
160
|
+
const certifications = await getLinkedinCertifications(identifier);
|
|
55
161
|
```
|
|
56
162
|
|
|
57
|
-
###
|
|
163
|
+
### `src/company.ts`
|
|
58
164
|
|
|
59
|
-
|
|
60
|
-
// Busca geral
|
|
61
|
-
const results = await search(
|
|
62
|
-
{
|
|
63
|
-
keywords: "desenvolvedor javascript",
|
|
64
|
-
filters: "List(resultType->PEOPLE)",
|
|
65
|
-
},
|
|
66
|
-
{ limit: 50 }
|
|
67
|
-
);
|
|
165
|
+
Funções exportadas:
|
|
68
166
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
167
|
+
- `getCompany(identifier: string): Promise<any>`
|
|
168
|
+
- Busca dados de uma empresa pelo `universalName` (slug da página).
|
|
169
|
+
- Exemplo de slug: `https://www.linkedin.com/company/microsoft/` -> `microsoft`.
|
|
170
|
+
|
|
171
|
+
Exemplo:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { getCompany } from "linkedin-api-voyager";
|
|
175
|
+
|
|
176
|
+
const company = await getCompany("microsoft");
|
|
77
177
|
```
|
|
78
178
|
|
|
79
|
-
###
|
|
179
|
+
### `src/posts.ts`
|
|
180
|
+
|
|
181
|
+
Funções exportadas:
|
|
182
|
+
|
|
183
|
+
- `parseResponsePostLinkedin(response: any, key: string, accumulatedData: any): any`
|
|
184
|
+
- Helper para selecionar itens do `included` a partir de `*elements`.
|
|
185
|
+
|
|
186
|
+
- `getCommentsByPostUrl(url: string, start = 0, limit = 50, accumulatedComments: unknown[] = []): Promise<unknown[]>`
|
|
187
|
+
- Busca comentários de um post (paginando recursivamente até acabar).
|
|
188
|
+
|
|
189
|
+
- `getPosts(): Promise<unknown[]>`
|
|
190
|
+
- Atualmente retorna `[]` (placeholder).
|
|
191
|
+
|
|
192
|
+
- `getPostLinkedin(url: string, commentsCount = 10, likesCount = 10): Promise<any>`
|
|
193
|
+
- Busca um post pelo slug da URL e retorna os dados do post e do autor.
|
|
194
|
+
|
|
195
|
+
- `getUserPosts({ identifier, start = 0, count = 50, accumulatedPosts = [] }): Promise<any>`
|
|
196
|
+
- Busca posts do usuário por `identifier` (publicIdentifier).
|
|
197
|
+
|
|
198
|
+
- `helperGetPosts(response: any, key: string, accumulatedPosts?: any, addFields?: Record<string, string>): any`
|
|
199
|
+
- Helper para extrair posts e contagens (likes, comentários, shares).
|
|
200
|
+
|
|
201
|
+
- `helperGetImageUrl(item: any): string`
|
|
202
|
+
- Helper para montar a URL de imagem, priorizando o maior artifact.
|
|
203
|
+
|
|
204
|
+
Exemplo (comentários):
|
|
80
205
|
|
|
81
|
-
```
|
|
206
|
+
```ts
|
|
82
207
|
import { getCommentsByPostUrl } from "linkedin-api-voyager";
|
|
83
208
|
|
|
84
|
-
// Obter todos os comentários de um post
|
|
85
209
|
const comments = await getCommentsByPostUrl(
|
|
86
210
|
"https://www.linkedin.com/feed/update/urn:li:activity-1234567890/",
|
|
87
|
-
0, // início
|
|
88
|
-
50 // limite por página
|
|
89
211
|
);
|
|
90
212
|
```
|
|
91
213
|
|
|
92
|
-
|
|
214
|
+
### `src/search.ts`
|
|
93
215
|
|
|
94
|
-
|
|
216
|
+
Constantes internas:
|
|
95
217
|
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
publicIdentifier: string;
|
|
99
|
-
firstName: string;
|
|
100
|
-
lastName: string;
|
|
101
|
-
fullName: string;
|
|
102
|
-
profilePicture: string;
|
|
103
|
-
backgroundPicture: string;
|
|
104
|
-
location: {
|
|
105
|
-
country: string;
|
|
106
|
-
city: string;
|
|
107
|
-
}
|
|
108
|
-
industry: string;
|
|
109
|
-
headline: string;
|
|
110
|
-
summary: string;
|
|
111
|
-
// ... outros campos
|
|
112
|
-
}
|
|
113
|
-
```
|
|
218
|
+
- `MAX_SEARCH_COUNT = 25` (limite máximo por chamada na busca geral)
|
|
114
219
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
[
|
|
119
|
-
{
|
|
120
|
-
id: string;
|
|
121
|
-
title: string;
|
|
122
|
-
companyName: string;
|
|
123
|
-
companyUrn: string;
|
|
124
|
-
universalName: string; // Nome universal da empresa
|
|
125
|
-
description: string;
|
|
126
|
-
location: string;
|
|
127
|
-
startDate: { year: number; month: number };
|
|
128
|
-
endDate: { year: number; month: number } | null; // null = ativo
|
|
129
|
-
// ... outros campos
|
|
130
|
-
}
|
|
131
|
-
]
|
|
132
|
-
```
|
|
220
|
+
Funções exportadas:
|
|
133
221
|
|
|
134
|
-
|
|
222
|
+
- `search(params: ISearchParams): Promise<SearchResponse>`
|
|
223
|
+
- Busca geral usando `query` e/ou `filters` (formato Voyager).
|
|
224
|
+
- Aceita paginação via `offset`.
|
|
135
225
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
description: string;
|
|
141
|
-
username: string;
|
|
142
|
-
companyPageUrl: string;
|
|
143
|
-
staffCount: number;
|
|
144
|
-
url: string;
|
|
145
|
-
location: string;
|
|
146
|
-
followerCount: number;
|
|
147
|
-
logo: object;
|
|
148
|
-
// ... outros campos
|
|
149
|
-
}
|
|
150
|
-
```
|
|
226
|
+
- `searchPeople(queryOrParams: string | ISearchPeopleParams): Promise<ISearchPeopleResponse>`
|
|
227
|
+
- Busca pessoas com helpers para montar filtros (networkDepth, regiões, empresas etc.).
|
|
228
|
+
|
|
229
|
+
Exemplo:
|
|
151
230
|
|
|
152
|
-
|
|
231
|
+
```ts
|
|
232
|
+
import { search, searchPeople } from "linkedin-api-voyager";
|
|
153
233
|
|
|
154
|
-
|
|
234
|
+
const res = await search({ query: "react developer" });
|
|
235
|
+
const people = await searchPeople({
|
|
236
|
+
query: "engenheiro de software",
|
|
237
|
+
regions: ["br:0"],
|
|
238
|
+
});
|
|
239
|
+
```
|
|
155
240
|
|
|
156
|
-
|
|
157
|
-
|
|
241
|
+
### `src/utils.ts`
|
|
242
|
+
|
|
243
|
+
Funções exportadas (helpers usados em parsing e normalização):
|
|
244
|
+
|
|
245
|
+
- `filterKeys(obj: any, keysToKeep: string[]): any`
|
|
246
|
+
- `filterOutKeys(obj: any, keysToIgnore: string[]): any`
|
|
247
|
+
- `getNestedValue(obj: any, path: string): any`
|
|
248
|
+
- `extractFields(data: any[], fieldsMap: Record<string, string>): any[]`
|
|
249
|
+
- `debugObjectStructure(obj: any, maxDepth = 3, currentDepth = 0): void`
|
|
250
|
+
- `resolveReferences(data: any, included: any[]): any`
|
|
251
|
+
- `extractDataWithReferences(elements: string[], included: any[], fieldsMap?: Record<string, string>): any[]`
|
|
252
|
+
- `debugResolvedStructure(elements: string[], included: any[], maxDepth = 2): void`
|
|
253
|
+
- `extractFieldsFromIncluded(included: any[], fields: string[]): Array<Record<string, any>>`
|
|
254
|
+
- `mergeExtraFields(mainData: any[], extraData: Array<Record<string, any>>, matchKey = "companyUrn"): any[]`
|
|
255
|
+
- `getDataIncludedForEntity(jsonData: Record<string, any>, entityUrn: string): any`
|
|
256
|
+
- `extractExperiences(jsonData: Record<string, any>): Array<{ role: string | null; idCompany: string | null; company: string | null; ... }>`
|
|
257
|
+
- `assert(value: unknown, message?: string | Error): asserts value`
|
|
258
|
+
- `getIdFromUrn(urn?: string): string | undefined`
|
|
259
|
+
- `getUrnFromRawUpdate(update?: string): string | undefined`
|
|
260
|
+
- `isLinkedInUrn(urn?: string): boolean`
|
|
261
|
+
- `parseExperienceItem(item: any, opts: { isGroupItem?: boolean; included: any[] }): ExperienceItem`
|
|
262
|
+
- `getGroupedItemId(item: any): string | undefined`
|
|
263
|
+
- `omit(inputObj: object, ...keys: string[]): object`
|
|
264
|
+
- `resolveImageUrl(vectorImage?: VectorImage): string | undefined`
|
|
265
|
+
- `resolveLinkedVectorImageUrl(linkedVectorImage?: LinkedVectorImage): string | undefined`
|
|
266
|
+
- `stringifyLinkedInDate(date?: LIDate): string | undefined`
|
|
267
|
+
- `normalizeRawOrganization(o?: RawOrganization): Organization`
|
|
268
|
+
|
|
269
|
+
Exemplo (mapear campos com path aninhado):
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import { extractFields } from "linkedin-api-voyager";
|
|
158
273
|
|
|
159
|
-
// Mapear campos específicos
|
|
160
274
|
const fieldsMap = {
|
|
161
275
|
nome: "firstName",
|
|
162
|
-
|
|
163
|
-
|
|
276
|
+
headline: "headline",
|
|
277
|
+
foto: "profilePicture.displayImageReferenceResolutionResult.vectorImage.rootUrl",
|
|
164
278
|
};
|
|
165
279
|
|
|
166
|
-
const
|
|
280
|
+
const mapped = extractFields([someObject], fieldsMap);
|
|
167
281
|
```
|
|
168
282
|
|
|
169
|
-
###
|
|
170
|
-
|
|
171
|
-
A biblioteca resolve automaticamente referências URN aninhadas, permitindo acesso direto a dados relacionados sem necessidade de mapeamento manual.
|
|
172
|
-
|
|
173
|
-
## ⚠️ Limitações e considerações
|
|
283
|
+
### `src/types.ts`
|
|
174
284
|
|
|
175
|
-
|
|
176
|
-
- Requer cookies válidos de uma sessão autenticada
|
|
177
|
-
- Respeite os termos de uso do LinkedIn
|
|
178
|
-
- Use com moderação para evitar bloqueios
|
|
179
|
-
- Não é uma API oficial do LinkedIn
|
|
285
|
+
Este arquivo exporta tipos e interfaces TypeScript usados pela biblioteca (por exemplo: `ISearchParams`, `ISearchPeopleParams`, `SearchResponse`, `Organization`, `ExperienceItem`).
|
|
180
286
|
|
|
181
|
-
##
|
|
287
|
+
## Limitações e considerações
|
|
182
288
|
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
289
|
+
- Usa endpoints internos do LinkedIn (Voyager), que podem mudar sem aviso.
|
|
290
|
+
- Requer cookies válidos de uma sessão autenticada.
|
|
291
|
+
- Use com moderação para reduzir risco de bloqueio.
|
|
292
|
+
- Respeite os termos de uso do LinkedIn.
|
|
186
293
|
|
|
187
|
-
##
|
|
294
|
+
## Licença
|
|
188
295
|
|
|
189
296
|
MIT
|
|
190
|
-
|
|
191
|
-
## 🤝 Contribuição
|
|
192
|
-
|
|
193
|
-
Contribuições são bem-vindas! Por favor, abra uma issue ou pull request.
|
|
194
|
-
|
|
195
|
-
## 📞 Suporte
|
|
196
|
-
|
|
197
|
-
Para dúvidas ou problemas, abra uma issue no repositório.
|
package/lib/company.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getCompany: (identifier: string) => Promise<any>;
|
package/lib/company.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getCompany = void 0;
|
|
13
|
+
const config_1 = require("./config");
|
|
14
|
+
const utils_1 = require("./utils");
|
|
15
|
+
const getCompany = (identifier) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
const response = yield (0, config_1.fetchData)(`/organization/companies?decorationId=com.linkedin.voyager.deco.organization.web.WebFullCompanyMain-12&q=universalName&universalName=${identifier}`);
|
|
17
|
+
const data = (0, utils_1.extractDataWithReferences)(response.data["*elements"], response.included);
|
|
18
|
+
const fieldsMap = {
|
|
19
|
+
id: "entityUrn",
|
|
20
|
+
name: "name",
|
|
21
|
+
description: "description",
|
|
22
|
+
username: "universalName",
|
|
23
|
+
companyPageUrl: "companyPageUrl",
|
|
24
|
+
staffCount: "staffCount",
|
|
25
|
+
url: "url",
|
|
26
|
+
companyIndustries: "*companyIndustries[0].localizedName",
|
|
27
|
+
location: "locationName",
|
|
28
|
+
jobSearchPageUrl: "jobSearchPageUrl",
|
|
29
|
+
phone: "phone",
|
|
30
|
+
followerCount: "followingInfo.followerCount",
|
|
31
|
+
backgroundCoverImage: "backgroundCoverImage.image",
|
|
32
|
+
logo: "logo.image",
|
|
33
|
+
permissions: "permissions",
|
|
34
|
+
};
|
|
35
|
+
return (0, utils_1.extractFields)(data, fieldsMap).map((item) => {
|
|
36
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
37
|
+
return (Object.assign(Object.assign({}, item), { id: item.id.split(":")[3], backgroundCoverImage: `${(_a = item.backgroundCoverImage) === null || _a === void 0 ? void 0 : _a.rootUrl}${(_d = (_c = (_b = item.backgroundCoverImage) === null || _b === void 0 ? void 0 : _b.artifacts) === null || _c === void 0 ? void 0 : _c.at(-1)) === null || _d === void 0 ? void 0 : _d.fileIdentifyingUrlPathSegment}`, logo: `${(_e = item.logo) === null || _e === void 0 ? void 0 : _e.rootUrl}${(_h = (_g = (_f = item.logo) === null || _f === void 0 ? void 0 : _f.artifacts) === null || _g === void 0 ? void 0 : _g.at(-1)) === null || _h === void 0 ? void 0 : _h.fileIdentifyingUrlPathSegment}` }));
|
|
38
|
+
})[0];
|
|
39
|
+
});
|
|
40
|
+
exports.getCompany = getCompany;
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const COOKIE_FILE_PATH = "linkedin_cookies.json";
|
|
2
|
+
export declare const API_BASE_URL = "https://www.linkedin.com/voyager/api";
|
|
3
|
+
export declare const AUTH_BASE_URL = "https://www.linkedin.com";
|
|
4
|
+
interface LinkedInCookies {
|
|
5
|
+
JSESSIONID: string;
|
|
6
|
+
li_at: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const saveCookies: (JSESSIONID: string, li_at: string) => Promise<void>;
|
|
10
|
+
export declare const loadCookies: () => Promise<LinkedInCookies | null>;
|
|
11
|
+
export declare const Client: (providedCookies?: {
|
|
12
|
+
JSESSIONID: string;
|
|
13
|
+
li_at: string;
|
|
14
|
+
}) => Promise<ReturnType<typeof api>>;
|
|
15
|
+
declare const api: ({ JSESSIONID, li_at }: {
|
|
16
|
+
li_at: string;
|
|
17
|
+
JSESSIONID: number;
|
|
18
|
+
}) => import("axios").AxiosInstance;
|
|
19
|
+
export declare const fetchData: (endpoint: string) => Promise<any>;
|
|
20
|
+
export {};
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.fetchData = exports.Client = exports.loadCookies = exports.saveCookies = exports.AUTH_BASE_URL = exports.API_BASE_URL = exports.COOKIE_FILE_PATH = void 0;
|
|
13
|
+
const fs = require("fs-extra");
|
|
14
|
+
const axios_1 = require("axios");
|
|
15
|
+
exports.COOKIE_FILE_PATH = "linkedin_cookies.json";
|
|
16
|
+
exports.API_BASE_URL = "https://www.linkedin.com/voyager/api";
|
|
17
|
+
exports.AUTH_BASE_URL = "https://www.linkedin.com";
|
|
18
|
+
// Função para salvar cookies no arquivo JSON
|
|
19
|
+
const saveCookies = (JSESSIONID, li_at) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
try {
|
|
21
|
+
const cookies = {
|
|
22
|
+
JSESSIONID,
|
|
23
|
+
li_at,
|
|
24
|
+
timestamp: Date.now(),
|
|
25
|
+
};
|
|
26
|
+
yield fs.ensureFile(exports.COOKIE_FILE_PATH);
|
|
27
|
+
yield fs.writeJson(exports.COOKIE_FILE_PATH, cookies, { spaces: 2 });
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
exports.saveCookies = saveCookies;
|
|
34
|
+
// Função para carregar cookies do arquivo JSON
|
|
35
|
+
const loadCookies = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
36
|
+
try {
|
|
37
|
+
const exists = yield fs.pathExists(exports.COOKIE_FILE_PATH);
|
|
38
|
+
if (!exists) {
|
|
39
|
+
throw new Error("Arquivo de cookies não encontrado");
|
|
40
|
+
}
|
|
41
|
+
const cookies = yield fs.readJson(exports.COOKIE_FILE_PATH);
|
|
42
|
+
// Verificar se os cookies têm a estrutura esperada
|
|
43
|
+
if (!cookies.JSESSIONID || !cookies.li_at) {
|
|
44
|
+
throw new Error("Cookies inválidos encontrados no arquivo");
|
|
45
|
+
}
|
|
46
|
+
return cookies;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
exports.loadCookies = loadCookies;
|
|
53
|
+
// Função para criar cliente com cookies automáticos
|
|
54
|
+
const Client = (providedCookies) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
let cookiesToUse;
|
|
56
|
+
const savedCookies = yield (0, exports.loadCookies)();
|
|
57
|
+
if (savedCookies) {
|
|
58
|
+
cookiesToUse = {
|
|
59
|
+
JSESSIONID: savedCookies.JSESSIONID,
|
|
60
|
+
li_at: savedCookies.li_at,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
if (providedCookies) {
|
|
65
|
+
yield (0, exports.saveCookies)(providedCookies.JSESSIONID, providedCookies.li_at);
|
|
66
|
+
cookiesToUse = providedCookies;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error("Nenhum cookie válido fornecido");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return api({
|
|
73
|
+
JSESSIONID: parseInt(cookiesToUse.JSESSIONID),
|
|
74
|
+
li_at: cookiesToUse.li_at,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
exports.Client = Client;
|
|
78
|
+
const api = ({ JSESSIONID, li_at }) => {
|
|
79
|
+
return axios_1.default.create({
|
|
80
|
+
baseURL: exports.API_BASE_URL,
|
|
81
|
+
headers: {
|
|
82
|
+
"accept-language": "pt-BR,pt;q=0.9,fr-FR;q=0.8,fr;q=0.7,en-US;q=0.6,en;q=0.5",
|
|
83
|
+
accept: "application/vnd.linkedin.normalized+json+2.1",
|
|
84
|
+
cookie: `li_at=${li_at}; JSESSIONID="ajax:${JSESSIONID}"`,
|
|
85
|
+
"csrf-token": `ajax:${JSESSIONID}`,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const fetchData = (endpoint) => __awaiter(void 0, void 0, void 0, function* () {
|
|
90
|
+
const api = yield (0, exports.Client)();
|
|
91
|
+
const response = yield api.get(endpoint);
|
|
92
|
+
return response.data;
|
|
93
|
+
});
|
|
94
|
+
exports.fetchData = fetchData;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./user"), exports);
|
|
18
|
+
__exportStar(require("./company"), exports);
|
|
19
|
+
__exportStar(require("./posts"), exports);
|
|
20
|
+
__exportStar(require("./search"), exports);
|
|
21
|
+
__exportStar(require("./utils"), exports);
|
|
22
|
+
__exportStar(require("./config"), exports);
|
package/lib/posts.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const parseResponsePostLinkedin: (response: any, key: string, accumulatedData: any) => any;
|
|
2
|
+
export declare const getCommentsByPostUrl: (url: string, start?: number, limit?: number, accumulatedComments?: unknown[]) => Promise<unknown[]>;
|
|
3
|
+
export declare const getPosts: () => Promise<never[]>;
|
|
4
|
+
export declare const getPostLinkedin: (url: string, commentsCount?: number, likesCount?: number) => Promise<any>;
|
|
5
|
+
export declare const getUserPosts: ({ identifier, start, count, accumulatedPosts, }: {
|
|
6
|
+
identifier: string;
|
|
7
|
+
start?: number;
|
|
8
|
+
count?: number;
|
|
9
|
+
accumulatedPosts?: unknown[];
|
|
10
|
+
}) => Promise<any[]>;
|
|
11
|
+
export declare const helperGetPosts: (response: any, key: string, accumulatedPosts?: any, addFields?: Record<string, string>) => any[];
|
|
12
|
+
export declare const helperGetImageUrl: (item: any) => any;
|