๐Ÿ‘จโ€๐Ÿ’ผLinkedin API for Python

Overview

linkedin_api

๐Ÿ‘จโ€๐Ÿ’ผ Linkedin API for Python

Build Status Documentation Status

No "official" API access required - just use a valid Linkedin account!

Programmatically send messages, get jobs, search profiles and more, all with a regular Linkedin user account!

Before using this project, please consult the Terms and Conditions and Legal Notice.

Installation

โš ๏ธ Python >= 3.6 required

pip3 install linkedin-api~=2.0.0a

Why v2.0.0a?

Example usage

from linkedin_api import Linkedin

# Authenticate using any Linkedin account credentials
api = Linkedin('[email protected]', '*******')

# GET a profile
profile = api.get_profile('billy-g')

# GET a profiles contact info
contact_info = api.get_profile_contact_info('billy-g')

# GET 1st degree connections of a given profile
connections = api.get_profile_connections('1234asc12304')

Documentation

For a complete reference documentation, see the documentation website.

Overview

This project attempts to provide a simple Python interface for the Linkedin API.

Do you mean the legit Linkedin API?

NO! To retrieve structured data, the Linkedin Website uses a service they call Voyager. Voyager endpoints give us access to pretty much everything we could want from Linkedin: profiles, companies, connections, messages, etc. - anything that you can see on linkedin.com, we can get from Voyager.

So specifically, this project aims to provide complete coverage for Voyager.

How do we do it?

How to contribute

Learn how to find endpoints

Development Setup

Dependencies

  • Python 3.7
  • A valid Linkedin user account (don't use your personal account, if possible)
  • pipenv (optional)

Development installation

  1. Create a .env config file. An example is provided in .env.example - you include at least all of the settings set there.

  2. Using pipenv...

    pipenv install --dev
    pipenv shell

Running tests

python -m pytest tests

Troubleshooting

I keep getting a CHALLENGE

Linkedin will throw you a curve ball in the form of a Challenge URL. We currently don't handle this, and so you're kinda screwed. We think it could be only IP-based (i.e. logging in from different location). Your best chance at resolution is to log out and log back in on your browser.

Known reasons for Challenge include:

  • 2FA
  • Rate-limit - "It looks like youโ€™re visiting a very high number of pages on LinkedIn.". Note - n=1 experiment where this page was hit after ~900 contiguous requests in a single session (within the hour) (these included random delays between each request), as well as a bunch of testing, so who knows the actual limit.

Please add more as you come across them.

Search problems

  • Mileage may vary when searching general keywords like "software" using the standard search method. They've recently added some smarts around search whereby they group results by people, company, jobs etc. if the query is general enough. Try to use an entity-specific search method (i.e. search_people) where possible.

In-depth overview

Voyager endpoints look like this:

https://www.linkedin.com/voyager/api/identity/profileView/tom-quirk

Or, more clearly

 ___________________________________ _______________________________
|             base path             |            resource           |
https://www.linkedin.com/voyager/api /identity/profileView/tom-quirk

They are authenticated with a simple cookie, which we send with every request, along with a bunch of headers.

To get a cookie, we POST a given username and password (of a valid Linkedin user account) to https://www.linkedin.com/uas/authenticate.

To find endpoints

We're looking at the Linkedin website and we spot some data we want. What now?

The most reliable method to find the relevant endpoint is to:

  1. view source

  2. command-f/search the page for some keyword in the data. This will exist inside of a <code> tag.

  3. Scroll down to the next adjacent element which will be another <code> tag, probably with an id that looks something like

    <code style="display: none" id="datalet-bpr-guid-3900675">
      {"request":"/voyager/api/identity/profiles/tom-quirk/profileView","status":200,"body":"bpr-guid-3900675"}
    </code>
  4. The value of request is the url! ๐Ÿค˜

You can also use the network tab in you browsers developer tools, but you will encounter mixed results.

How Clients query Voyager

Linkedin seems to have developed an internal query language/syntax where Clients (i.e. front-ends like linkedin.com) to specify what data they want (similar to the GraphQL concept). If anyone knows what this is, I'd love to know!.

Here's an example of making a request for an organisation's name and groups (the Linkedin groups it manages):

/voyager/api/organization/companies?decoration=(name,groups*~(entityUrn,largeLogo,groupName,memberCount,websiteUrl,url))&q=universalName&universalName=linkedin

The "querying" happens in the decoration parameter, which looks like

(
    name,
    groups*~(entityUrn,largeLogo,groupName,memberCount,websiteUrl,url)
)

So here, we request an organisation name, and a list of groups, where for each group we want largeLogo, groupName, etc.

Different endpoints use different parameters (and perhaps even different syntaxes) to specify these queries. Notice that the above query had a parameter q whose value was universalName; the query was then specified with the decoration parameter.

In contrast, the /search/cluster endpoint uses q=guided, and specifies its query with the guided parameter, whose value is something like

List(v->PEOPLE)

It could be possible to document (and implement a nice interface for) this query language - as we add more endpoints to this project, I'm sure it will become more clear if such a thing would be possible (and if it's worth it).

Terms and Conditions

By using this project, you agree to the following Terms and Conditions. We reserve the right to block any user of this repository that does not meet these conditions.

Usage

This project may not be used for any of the following:

  • Commercial use
  • Spam
  • Storage of any Personally Identifiable Information
  • Personal abuse (i.e. verbal abuse)

Legal

This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Linkedin or any of its affiliates or subsidiaries. This is an independent and unofficial API. Use at your own risk.

This project violates Linkedin's User Agreement Section 8.2, and because of this, Linkedin may (and will) temporarily or permanently ban your account. We are not responsible for your account being banned.

Versioning Note

Tl;dr: Don't use anything < v2.0.0a.

Releases/tags for this package have not been kept up to date with changes and thus versions (like v1.0.0) are misleading and do not represent "stability". Eventually, v2.0.0 will be the "stable" release.

Comments
  • Support ability to send Linkedin connection requests

    Support ability to send Linkedin connection requests

    I.e. Add people on Linkedin

    POST

    {"trackingId":"XVpxyROJQ1ybTCQtEFrl8A==","invitations":[],"excludeInvitations":[],"invitee":{"com.linkedin.voyager.growth.invitation.InviteeProfile":{"profileId":"<profile_id>"}}}
    

    to url

    /voyager/api/growth/normInvitations
    
    enhancement linkedin API endpoint 
    opened by tomquirk 19
  • Added add_connection functionality

    Added add_connection functionality

    Fixes #10, #133

    • Added a function to generate a random TrackingId
    • Added add_connection functionality

    Do let me know how I could fix the tests as well.

    opened by abinpaul1 16
  • search_people with regions fails

    search_people with regions fails

    I run the code listed in the examples (and other attempts)

    results = linkedin.search_people( keywords='software,lol', connection_of='AC000120303', network_depth='F', regions=[4909], industries=[29, 1] )

    but I got this error


    in search_people filters.append(f'geoRegion->{"|".join(regions)}') TypeError: sequence item 0: expected str instance, int found


    bug 
    opened by Ulixestoitaca 15
  • get all posts from profile

    get all posts from profile

    Hi guys,

    Hope you are all well !

    I was wondering if I can fetch the list of all posts (for eg, https://www.linkedin.com/in/philipvollet/detail/recent-activity/shares) with linkedin-api ?

    Thanks for your inputs and insights on that.

    Cheers, X

    linkedin API endpoint 
    opened by paper2code-bot 12
  • `search_jobs` doesn't work

    `search_jobs` doesn't work

    I got this error:

    jobs = api.search_jobs(keywords='software engineer',experience='2',job_type='F')
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-7-e8676eef6663> in <module>()
    ----> 1 jobs = api.search_jobs(keywords='software engineer',experience='2',job_type='F')
    
    TypeError: search_jobs() got an unexpected keyword argument 'experience'
    

    I installed with

    pip3 install linkedin-api~=2.0.0a
    
    opened by khangly 11
  • search_people or search always returns same first result that found something

    search_people or search always returns same first result that found something

    When calling search_people or search multiple times, as soon as there is a result these methods will keep returning that same result for all subsequent searches.

    bug 
    opened by woutwoot 11
  • Add support for creating a new conversation

    Add support for creating a new conversation

    I can't send param's to this function. I notice that you put a comment line that

    # passing 'params' doesn't work properly, think it's to do with List(). 
    # Might be a bug in 'requests' ? 
    

    Is there any quick fix for this? I really need this.

    linkedin API endpoint needs investigation 
    opened by cyb3rsalih 9
  • Improve authentication

    Improve authentication "anti-bot-detection" mechanism

    Not sure if you've encountered this case, but the authentication sometimes doesn't work for me. The following exception will be thrown out:

    res.status_code 401
    Traceback (most recent call last):
      File "F:/linkedin-api/examples/basic.py", line 60, in <module>
        linkedin = Linkedin(credentials['username'], credentials['password'])
      File "F:\linkedin-api\linkedin_api\linkedin.py", line 30, in __init__
        self.client.authenticate(username, password)
      File "F:\linkedin-api\linkedin_api\client.py", line 102, in authenticate
        raise Exception()
    Exception
    

    I am thinking it might be the case that LinkedIn is blocking the API for some reason, but the account itself is fine (I can still login thru the web portal) - so I am wondering if you've encountered this before?

    enhancement 
    opened by xiaoyongzhu 9
  • linkedin_api.client.ChallengeException: CHALLENGE

    linkedin_api.client.ChallengeException: CHALLENGE

    As mentioned in Readme. Challenge error is coming because of continuous requests. But it is not true in my case. CHALLENGE error is coming after 1st request. After some analysis, I found out that this is happening after executing self.client.authenticate(username, password) function in linkdedin.py file. After executing this script one-time LinkedIn in sending me following mail:

    Hi XYZ, ย  To make sure you continue having the best experience possible on LinkedIn, we're regularly monitoring our site and the Internet to keep your account information safe. We've recently noticed a potential risk to your LinkedIn account coming from outside LinkedIn and just to be safe, we've locked your account for now. You'll need to reset your password in order to unlock your account. Here's how: Go to the LinkedIn website. Next to the password field, click the "Forgot your password" link, and enter your email address. You'll get an email from LinkedIn asking you to click a link that will help you reset your password. Once you've reset your password, a confirmation email will be sent to the confirmed email addresses on your account.

    opened by Vikku14 8
  • AttributeError: 'Linkedin' object has no attribute 'add_connection'

    AttributeError: 'Linkedin' object has no attribute 'add_connection'

    I'm using latest version of linkedin-api yet I'm getting this error:

    ERROR:

    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-5-68dfe11587c3> in <module>
          1 # for user in search_ppl:
    ----> 2 api.add_connection(profile_public_id='user-profile-here', message='some message here')
    
    AttributeError: 'Linkedin' object has no attribute 'add_connection'
    

    After running pip show linkedin-api

    Name: linkedin-api
    Version: 2.0.0a5
    Summary: Python wrapper for the Linkedin API
    Home-page: https://github.com/tomquirk/linkedin-api
    Author: Tom Quirk
    Author-email: [email protected]
    License: MIT
    Location: c:\users\hamza\appdata\local\programs\python\python39\lib\site-packages
    Requires: beautifulsoup4, requests, lxml
    Required-by: 
    

    CODE:

    api.add_connection(profile_public_id='user-profile-here', message='some message here')
    
    opened by mhmzdev 7
  • Linkedin function not working

    Linkedin function not working

    Hi tomquirk,

    Thank you for your great package! However, as a newbie, I met several problems since the install step.

    • It seems -e should be removed from the Installation step.

    • And after I load the package, I can't even use the first step by Linkedin function. For example, this is not working api = Linkedin('[email protected]', 'iheartmicrosoft'). And the error is 'CookieRepository' object has no attribute 'logger'.

    I would be appreciated if you could tell me how to solve this problem. And my system is Windows 10 pro, Python 3.7.3 with Anaconda. Thanks for your reply!

    Sheng

    bug 
    opened by marc233 7
  • JSON decode error, no data on getting profile

    JSON decode error, no data on getting profile

    The package worked for me a few weeks ago but is now no longer working for some reason.

    Here's my simple code:

    from linkedin_api import Linkedin
    
    api: Unknown  = Linkedin('***', '***')
    
    # GET a profile
    profile: Unknown  = api.get_profile('billy-g')
    print(profile)
    

    When using the https://github.com/tomquirk/linkedin-api.git version of the package, this fails with

    Traceback (most recent call last):
      File "/Users/hima/Workspace/del/.venv/lib/python3.10/site-packages/requests/models.py", line 971, in json
        return complexjson.loads(self.text, **kwargs)
      File "/Users/hima/.pyenv/versions/3.10.4/lib/python3.10/json/__init__.py", line 346, in loads
        return _default_decoder.decode(s)
      File "/Users/hima/.pyenv/versions/3.10.4/lib/python3.10/json/decoder.py", line 337, in decode
        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
      File "/Users/hima/.pyenv/versions/3.10.4/lib/python3.10/json/decoder.py", line 355, in raw_decode
        raise JSONDecodeError("Expecting value", s, err.value) from None
    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/Users/hima/Workspace/del/run.py", line 6, in <module>
        profile = api.get_profile('billy-g')
      File "/Users/hima/Workspace/del/.venv/lib/python3.10/site-packages/linkedin_api/linkedin.py", line 622, in get_prof
    ile
        data = res.json()
      File "/Users/hima/Workspace/del/.venv/lib/python3.10/site-packages/requests/models.py", line 975, in json
        raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
    requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    
    

    When using the 2.0.0a version of the package, it fails during authentication instead with

    Traceback (most recent call last):
      File "/Users/hima/Workspace/del/run.py", line 3, in <module>
        api = Linkedin('***', '***')
      File "/Users/hima/Workspace/del/.venv/lib/python3.10/site-packages/linkedin_api/linkedin.py", line 69, in __init__
        self.client.authenticate(username, password)
      File "/Users/hima/Workspace/del/.venv/lib/python3.10/site-packages/linkedin_api/client.py", line 99, in authenticat
    e
        self._fetch_metadata()
      File "/Users/hima/Workspace/del/.venv/lib/python3.10/site-packages/linkedin_api/client.py", line 122, in _fetch_met
    adata
        ).attrs["content"]
    AttributeError: 'NoneType' object has no attribute 'attrs'
    

    I'm on python 3.10.4

    Any ideas why?

    opened by himat 1
  • Version 2.0.0 requires lxml that cannot be installed in mac m2

    Version 2.0.0 requires lxml that cannot be installed in mac m2

    Hello, i tried to install version 2, however, due to problems with lxml installation i cannot manage to install the lastest version, only the unmaintained 1.0.0. Anyone can help?

    opened by manuelrech 0
  • Search Companies Filters

    Search Companies Filters

    Has anyone successfully managed to add filters to the search companies such as location, industry and company size??

    I have tried to play with the code but to no success currently

    opened by SIF-FCHIARI 2
  • How to get saved posts?

    How to get saved posts?

    Hi, I would like to retrieve my saved posts. The URL is https://www.linkedin.com/my-items/saved-posts

    I believed I found the query using the Chrome Devtools but it doesn't work. I get an HTTP 400 error ("Bad request")

    Do you think it's possible to retrieve the saved posts?


    Here the code I use:

    api = Linkedin('<login>', '<password>')
    params = {
            "decorationId": "com.linkedin.voyager.dash.deco.search.SearchClusterCollection-169",
            "q": "all",
            "query":  "(flagshipSearchIntent:SEARCH_MY_ITEMS_SAVED_POSTS)",
            "start": 0
        }
    api._fetch(f"/search/dash/clusters", params=params)  # get a 400 error here
    
    opened by apallier 0
  • Add method to get social reactions for a post.

    Add method to get social reactions for a post.

    This shows likes, etc. for a post.

    In [2]: from linkedin_api import Linkedin
    
    In [3]: api = Linkedin(USERNAME, PASSWORD)
    
    In [4]: reactions = api.get_social_reactions("urn:li:activity:6975230311307644928", max_results=10)
    
    In [5]: reactions[0]
    {'actor': {'profileUrn': {'entityUrn': 'urn:li:fsd_profile:ACoAABO7kRoBn-gddYTjVljt4Ox54a6jjuE-5pc',
    ...
    
    opened by kjoconnor 0
Releases(2.0.0-alpha.4)
Owner
Tom Quirk
Tom Quirk
A Discord Bot that tracks and displays cryptocurrencies using the CoinMarketCap API

PyBo - A Crypto Inspired Discord Bot Pybo (paษช boสŠ) is a Discord bot that utilizes the discord.py API wrapper to run the bot. Pybo also integrates the

0 Nov 17, 2022
A tool to build scripts to toggle between minimal & default services in Windows based on user defined lists.

A tool to build scripts to toggle between minimal & default services in Windows based on user defined lists.

AMIT 29 Jan 01, 2023
๐Ÿ“ˆ A Discord bot for displaying the download stats of a repository made with Python, the Hikari API and PostgreSQL.

๐Ÿ“ˆ axyl-stats axyl-stats is a Discord bot made with Python (with the Hikari API wrapper) and PostgreSQL, used as a download counter for a GitHub repo.

Angelo-F 2 May 14, 2022
Amanda-A next gen powerful telegram group manager bot for manage your groups and have fun with other cool modules.

Amanda-A next gen powerful telegram group manager bot for manage your groups and have fun with other cool modules.

Team Amanda 4 Oct 21, 2022
TeslaPy - A Python implementation based on unofficial documentation of the client side interface to the Tesla Motors Owner API

TeslaPy - A Python implementation based on unofficial documentation of the client side interface to the Tesla Motors Owner API, which provides functiona

Tim Dorssers 233 Dec 30, 2022
Pack up to 3MB of data into a tweetable PNG polyglot file.

tweetable-polyglot-png Pack up to 3MB of data into a tweetable PNG polyglot file. See it in action here: https://twitter.com/David3141593/status/13719

David Buchanan 2.4k Dec 29, 2022
python3.5+ hubspot client based on hapipy, but modified to use the newer endpoints and non-legacy python

A python wrapper around HubSpot's APIs, for python 3.5+. Built initially around hapipy, but heavily modified. Check out the documentation here! (thank

Jacobi Petrucciani 140 Dec 21, 2022
Discord raid tool!

GANG Multi Tool Menu: -- YOUTUBE TUTORIAL! Features: Most Advanced Multi Tool! Spammer DM Spammer Friend Spammer Reaction Spam WebhookSpammer Typing

1 Feb 13, 2022
Changes your desktop wallpaper based on the weather.

WallPaperChanger ๐Ÿ–ผ๏ธ Description โ›ˆ๏ธ This Python script changes your desktop wallpaper based on the weather. Cloning ๐ŸŒ€ $ git clone https://github.com/

Clarence Yang 74 Nov 29, 2022
A simple Discord bot that notifies users of new Abitti versions

A simple Discord bot that notifies users of new Abitti versions. New features might be added later on. If you have good ideas, feel free to do a PR.

1 Feb 11, 2022
A free sniper bot built to work with PancakeSwap: Router V2

Pancakeswap Sniper Bot PancakeSwap sniper bot. Automated sniping bot to snipe crypto coin launches. How it works The sniping bot can be used in three

89 Aug 06, 2022
Cรณdigo para trabalho com o dataset Wine em Python

Um perceptron multicamadas (MLP) รฉ uma rede neural artificial feedforward que gera um conjunto de saรญdas a partir de um conjunto de entradas. Um MLP รฉ

Hemili Beatriz 1 Jan 08, 2022
Pluggable Telethon - Telegram UserBot

A stable pluggable Telegram userbot, based on Telethon.

Team Ultroid 2.3k Dec 30, 2022
This is a crypto trading bot that scans the Binance Annoucements page for new coins, and places trades on Gateio

gateio-trading-bot-binance-announcements This Gateio x Binance cryptocurrency trading bot scans the Binance Announcements page and picks up on new coi

Andrei 1.2k Jan 01, 2023
Telegram Google Translater Bot

Google-Translater-Bot Hey Mo Tech, I am simple Google Translater Bot. I can translate any language to you selected language Team Mo Tech Deploy To Her

21 Dec 01, 2022
Modern, privacy-friendly, and detailed web analytics that works without cookies or JS.

Modern, privacy-friendly, and cookie-free web analytics. Getting started ยป Screenshots โ€ข Features โ€ข Office Hours Motivation There are a lot of web ana

R. Miles McCain 2.1k Jan 03, 2023
A play store search telegram bot

Play-Store-Bot A play store search telegram bot Made with Python3 (C) @FayasNoushad Copyright permission under MIT License License - https://github.c

Fayas Noushad 17 Oct 28, 2022
A very simple Salesforce.com REST API client for Python

Simple Salesforce Simple Salesforce is a basic Salesforce.com REST API client built for Python 3.5, 3.6, 3.7 and 3.8. The goal is to provide a very lo

simple salesforce 1.4k Dec 29, 2022
A collection of scripts to steal BTC from Lightning Network enabled custodial services. Only for educational purpose! Share your findings only when design flaws are fixed.

Lightning Network Fee Siphoning Attack LN-fee-siphoning is a collection of scripts to subtract BTC from Lightning Network enabled custodial services b

Reckless_Satoshi 14 Oct 15, 2022