👨‍💼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
livestream-chat: Overlay para chats de livestreams

livestream-chat Overlay para chats de livestreams. Inicialmente para rodar dentro do browser do obs-studio. TODO: Issues iniciais Suporte a API do You

Eduardo Mendes 10 Dec 16, 2022
💰 Import your ING Germany bank statements via FinTS into YNAB.

Import your ING Germany bank statements via FinTS into YNAB. Setup Before setting this up, please register your FinTS product – it's free and takes on

Arne Bahlo 23 Jan 21, 2022
Trading bot - A Trading bot With Python

Trading_bot Trading bot intended for 1) Tracking current prices of tokens 2) Set

Tymur Kotkov 29 Dec 01, 2022
Vhook: A Discord webhook spammer / deleter open source coded by vesper

Vhook_Spammer Vhook is a advanced Discord webhook spammer / deleter with embeds,

Vesper 17 Nov 13, 2022
Pixiv 爬虫,使用 Python 实现。支持批量下载、上传到图床。

用 Python 实现的 Pixiv 爬虫,支持批量下载和上传。 随机图片 API: https://loliapi.ml/ Deploy Github Action 集成部署 建议使用本方法部署,相较于本地部署,无需搭建环境,全程在线上完成。并且使用国外服务器下载、上传,网络更加通畅。 Fork

18 Feb 26, 2022
Telegram music & video bot direct play music

⚡ NOINOI MUSIC PLAYER 🎵 SUPERFAST MUSIC BOT WHO CAN DIRECT PLAY SONG ON TELEGRAM VOICE CHAT ALSO CAN PLAY VIDEO ON VOICE CHATS ✨ Heroku Deploy YOU CA

noinoi-X 1 Dec 28, 2021
Бот - Гуль для твоего телеграм аккаунта

Я - Гуль (бот), теперь работает в чатах Отблагодарить автора за проделанную работу можно здесь Помощь с установкой тут Установка на Андроид После уста

57 Nov 06, 2022
Telegram Group Management Bot based on Pyrogram

Komi-San Telegram Group Management Bot based on Pyrogram More updates coming soon Support Group Open a Pull request if you wana contribute Example for

33 Nov 07, 2022
Update your World of Warcraft AddOns hosted on GitHub

AddOns Update Tool Tool to update World of Warcraft AddOns hosted on GitHub Features Pure Python: only Dulwich and Colorlog Multithreaded tasks Manual

Mr. Alchemist 16 Dec 06, 2022
SickNerd aims to slowly enumerate Google Dorks via the googlesearch API then requests found pages for metadata

CLI tool for making Google Dorking a passive recon experience. With the ability to fetch and filter dorks from GHDB.

Jake Wnuk 21 Jan 02, 2023
Nft-maker - Create your own NFT!

nft-maker How to If you're going to use this program, change the pictures in the "images" folder. All images must be of the same resolution and size.

Georgii Arakelian 4 Mar 13, 2022
A repository of publicly verifiable token Sale contracts

Token-Sale-Plutus-Contract A repository of publicly verifiable token sale and royalty contracts. This will be the storage solution since it is easily

Logical Mechanism 29 Aug 18, 2022
Info gathering | API hacketarget.com

InfoFetch Info gathering | API hackertarget.com set-up: apt-get install python3 pip3 install requests apt-get install git git clone https://github.com

Muhammed Rizad 4 Nov 22, 2021
自动每天给女友发邮件

github acitons 发邮件 python 脚本 每天 7点半左右给女朋友发送邮件 天气来自: http://www.tianqiapi.com/ 文字图片来源:http://wufazhuce.com/ 风景图:https://qqlykm.cn/api/fengjing 土味情话:htt

gogobody 7 May 12, 2022
Spodcast is a caching Spotify podcast to RSS proxy

Spodcast Spodcast is a caching Spotify podcast to RSS proxy. Using Spodcast you can follow Spotify-hosted netcasts/podcasts using any player which sup

Frank de Lange 260 Jan 01, 2023
An advanced api client for python botters.

[ALPHA] pybotters An advanced api client for python botters. 📌 Description pybottersは仮想通貨botter向けのPythonライブラリです。複数取引所に対応した非同期APIクライアントであり、bot開発により素晴ら

261 Dec 31, 2022
An open source, multipurpose, configurable discord bot that does it all

Spacebot - Discord Bot Music, Moderation, Fun, Utilities, Games and Fully Configurable. Overview • Contributing • Self hosting • Documentation (not re

Dhravya Shah 41 Dec 10, 2022
Coinbase Listing Sniper

Coinbase Listing Sniper Script that listens to the @CoinbaseAssets twitter to find information about new Coinbase listings, and automatically buys 100

4 Oct 26, 2022
Discord bot that manages expiration of roles with subscriptions!

Discord bot that manages expiration of roles with subscriptions!

Chakeaw__ 3 Apr 28, 2022
Script for polybar to display and control media(not only Spotify) using DBus.

polybar-now-playing Script for polybar to display and control media(not only Spotify) using DBus Python script to display and control current playing

Dope Wizard 48 Dec 31, 2022