Example Linkedin Sign In avatar
Example Linkedin Sign In

Deprecated

Pricing

Pay per usage

Go to Store
Example Linkedin Sign In

Example Linkedin Sign In

Deprecated

Developed by

Jakub Drobník

Jakub Drobník

Maintained by Community

Shows you how to sign in to LinkedIn with an Apify actor with Puppeteer image. Note that it does not solve the anti-captcha.

0.0 (0)

Pricing

Pay per usage

1

Total users

67

Monthly users

1

Last modified

3 years ago

Dockerfile

# This is a template for a Dockerfile used to run acts in Actor system.
# The base image name below is set during the act build, based on user settings.
# IMPORTANT: The base image must set a correct working directory, such as /usr/src/app or /home/user
FROM apify/actor-node-puppeteer
# Second, copy just package.json and package-lock.json since it should be
# the only file that affects "npm install" in the next step, to speed up the build
COPY package*.json ./
# Install NPM packages, skip optional and development dependencies to
# keep the image small. Avoid logging too much and print the dependency
# tree for debugging
RUN npm --quiet set progress=false \
&& npm install --only=prod --no-optional \
&& echo "Installed NPM packages:" \
&& (npm list --all || true) \
&& echo "Node.js version:" \
&& node --version \
&& echo "NPM version:" \
&& npm --version
# Copy source code to container
# Do this in the last step, to have fast build if only the source code changed
COPY --chown=node:node . ./
# NOTE: The CMD is already defined by the base image.
# Uncomment this for local node inspector debugging:
# CMD [ "node", "--inspect=0.0.0.0:9229", "main.js" ]

package.json

{
"name": "apify-project",
"version": "0.0.1",
"description": "",
"author": "It's not you it's me",
"license": "ISC",
"dependencies": {
"apify": "latest"
},
"scripts": {
"start": "node main.js"
}
}

main.js

1const Apify = require('apify');
2
3const humanDelay = ms => (Math.random() + 1) * ms;
4
5const saveScreen = async (page, key) => {
6 const screenshotBuffer = await page.screenshot();
7 await Apify.setValue(key, screenshotBuffer, { contentType: 'image/png' });
8};
9
10/**
11 * Use this class for sign in to linkedin
12 * NOTE: linkedin sometimes can verified user with pin, which is sent to user email. In this case
13 * forward email to 8mxmzpus@robot.zapier.com. It is email parser, which send pin direct to act.
14 * usage: const browser = await Apify.launchPuppeteer({ proxyUrl: proxy.href, headless: true });
15 * const page = await browser.newPage(); const linkedinUtils = new LinkedinUtils(page, user, pwd)
16 * linkedinUtils.login();
17 */
18class LinkedinUtils {
19 /**
20 * @param page - instance of puppeteer page object
21 * @param user - linkedin user
22 * @param pwd - linkedin user password
23 */
24 constructor(page, user, pwd, debugMode = false) {
25 this.page = page;
26 this.user = user;
27 this.pwd = pwd;
28 this.loginPageUrl = 'https://www.linkedin.com/';
29 this.debugMode = debugMode;
30 this.signInCount = 0;
31 }
32
33 async login() {
34 console.log('Sign in ...');
35 if (this.signInCount > 5) {
36 throw new Error('Failed to sign in, check user and password');
37 return;
38 }
39 await this.page.goto(this.loginPageUrl);
40 const userInput = await this.page.$('#login-email');
41 await userInput.type(this.user, humanDelay(100));
42 const pwdInput = await this.page.$('#login-password');
43 await pwdInput.type(this.pwd, { delay: humanDelay(100) });
44 await this.page.click('#login-submit', { delay: humanDelay(100) });
45 await new Promise(resolve => setTimeout(resolve, humanDelay(5000)));
46
47 // Page can contain verification code
48 const isVerifCode = await this.isVerifCode();
49 if (isVerifCode) await this.fillVerifCode();
50
51 // Check if we signed in
52 const isLogged = await this.isAfterLoginPage();
53 if (!isLogged) {
54 //noCaptchaIframe
55 const isCaptcha = await this.isCaptcha();
56 if (isCaptcha) await this.solveCaptcha();
57 const isPhoneForm = await this.isPhoneForm();
58 if (isPhoneForm) await this.page.click('button.secondary-action', { delay: humanDelay(100) });
59 await saveScreen(this.page, 'failed-sign-in');
60 console.log('Sign in again ...');
61 this.signInCount++;
62 return this.login();
63 }
64 }
65
66 async isAfterLoginPage() {
67 const profileButton = !!await this.page.$('.nav-item--profile');
68 return profileButton;
69 }
70
71 async isVerifCode() {
72 const isVerifCode = !!await this.page.$('#verification-code');
73 return isVerifCode;
74 }
75
76 async isCaptcha() {
77 const isCaptcha = !!await this.page.$('#noCaptchaIframe');
78 return isCaptcha;
79 }
80
81 async isPhoneForm() {
82 const isPhoneForm = !!await this.page.$('input#phone-number');
83 return isPhoneForm;
84 }
85
86 async solveCaptcha() {
87 console.log('Star solving captcha...');
88 throw new Error('We found captcha!');
89 }
90
91 async fillVerifCode() {
92 const triedPins = [];
93 const startedAt = new Date();
94 while (true) {
95 const isVerified = await this.isVerifCode();
96 if (!isVerified) break;
97 // check timeout
98 if ((new Date() - startedAt) > 10 * 60 * 1000) {
99 console.log('Waiting for verification code timeouts');
100 break;
101 }
102 console.log('Verification code is needed');
103 if (this.debugMode) await saveScreen(this.page, 'verifCodeForm');
104 // Pin code with key email
105 const object = await Apify.client.keyValueStores.getRecord({
106 storeId: 'Zu2366Fzvw66gMjEk',
107 key: this.user.replace('@', '(at)'),
108 });
109 const emailPin = (object && object.body) ? object.body: '';
110 // Pin code without key email
111 // NOTE: sometimes we can recognise email from email with pin and we save pin with nomail key
112 const objectWithoutMail = await Apify.client.keyValueStores.getRecord({
113 storeId: 'Zu2366Fzvw66gMjEk',
114 key: 'nomail',
115 });
116 const noEmailPin = (objectWithoutMail && objectWithoutMail.body) ? objectWithoutMail.body : '';
117
118 const tryPin = (!emailPin || triedPins.includes(emailPin)) ? noEmailPin : emailPin;
119 console.log(`DEBUG: emailPin: ${emailPin}, noEmailPin: ${noEmailPin}, tryPin: ${tryPin}`);
120 if (tryPin) {
121 if (triedPins.includes(tryPin)) {
122 console.log(`We tried this ${tryPin} pin yet`);
123 } else if (tryPin === 'newCode') {
124 console.log('Pin is newCode we clicked on reset pin button');
125 await this.page.click('#resendCodeATOPinChallenge');
126 } else {
127 console.log(`Try fill pin from store: ${tryPin}`);
128 const codeInput = await this.page.$('#verification-code');
129 // clean exist value TODO: Find better approach
130 await this.page.$eval('#verification-code', (el) => {
131 el.value = '';
132 });
133 await codeInput.type(tryPin, { delay: humanDelay(100) });
134 await this.page.click('form[name="ATOPinChallengeForm"] input[name="signin"]', { delay: humanDelay(100) });
135 triedPins.push(tryPin);
136 }
137 } else {
138 console.log('Pin is not in kvs');
139 }
140 await new Promise(resolve => setTimeout(resolve, humanDelay(8000)));
141 }
142 }
143}
144
145Apify.main(async () => {
146 const input = await Apify.getValue('INPUT');
147
148 const user = input.user || process.env.USER;
149 const pwd = input.pwd || process.env.PWD;
150 const proxyUrl = input.proxyUrl || process.env.PROXY_URL;
151
152 console.log('Launching Puppeteer...');
153 const opts = {
154 args: [
155 '--disable-web-security',
156 ],
157 };
158 if (proxyUrl) opts.proxyUrl = input.proxyUrl;
159
160 const browser = await Apify.launchPuppeteer(opts);
161
162 const page = await browser.newPage();
163 await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko');
164
165 const linkedinUtils = new LinkedinUtils(page, user, pwd);
166 await linkedinUtils.login();
167
168 // Crawl linkedin as logged user
169 await page.goto('https://www.linkedin.com/mynetwork/');
170 await new Promise(resolve => setTimeout(resolve, humanDelay(8000)));
171 const networkCount = await page.$eval('h3.mn-connections-summary__count', el => el.innerText);
172 console.log(`You have ${networkCount} people in your linkedin network.`);
173
174 console.log('Closing Puppeteer...');
175
176 await browser.close();
177
178 await Apify.setValue('OUTPUT', { networkCount });
179
180 console.log('Done.');
181});