Example Linkedin Sign In avatar
Example Linkedin Sign In
Deprecated
View all Actors
This Actor is deprecated

This Actor is unavailable because the developer has decided to deprecate it. Would you like to try a similar Actor instead?

See alternative Actors
Example Linkedin Sign In

Example 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 --chown=node:node . ./
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