Example Linkedin Sign In
DeprecatedView all Actors
This Actor is unavailable because the developer has decided to deprecate it. Would you like to try a similar Actor instead?
See alternative ActorsExample Linkedin Sign In
drobnikj/linkedin-sign-in-example
Shows you how to sign in to LinkedIn with an Apify actor with Puppeteer image. Note that it does not solve the anti-captcha.
Dockerfile
1# This is a template for a Dockerfile used to run acts in Actor system.
2# The base image name below is set during the act build, based on user settings.
3# IMPORTANT: The base image must set a correct working directory, such as /usr/src/app or /home/user
4FROM apify/actor-node-puppeteer
5
6# Second, copy just package.json and package-lock.json since it should be
7# the only file that affects "npm install" in the next step, to speed up the build
8COPY package*.json ./
9
10# Install NPM packages, skip optional and development dependencies to
11# keep the image small. Avoid logging too much and print the dependency
12# tree for debugging
13RUN npm --quiet set progress=false \
14 && npm install --only=prod --no-optional \
15 && echo "Installed NPM packages:" \
16 && (npm list --all || true) \
17 && echo "Node.js version:" \
18 && node --version \
19 && echo "NPM version:" \
20 && npm --version
21
22# Copy source code to container
23# Do this in the last step, to have fast build if only the source code changed
24COPY . ./
25
26# NOTE: The CMD is already defined by the base image.
27# Uncomment this for local node inspector debugging:
28# CMD [ "node", "--inspect=0.0.0.0:9229", "main.js" ]
package.json
1{
2 "name": "apify-project",
3 "version": "0.0.1",
4 "description": "",
5 "author": "It's not you it's me",
6 "license": "ISC",
7 "dependencies": {
8 "apify": "latest"
9 },
10 "scripts": {
11 "start": "node main.js"
12 }
13}
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});
Developer
Maintained by Community
Categories