👨‍💼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 Simple Advance Auto Filter Bot Complete Rewritten Version Of Adv-Filter-Bot

Adv Auto Filter Bot This Is Just An Simple Advance Auto Filter Bot Complete Rewritten Version Of Adv-Filter-Bot.. Just Sent Any Text As Query It Will

TeamShadow 4 Dec 10, 2021
A melhor maneira de atender seus clientes no Telegram!

Clientes.Chat Sobre o serviço Configuração Banco de Dados Variáveis de Ambiente Docker Python Heroku Contribuição Sobre o serviço A maneira mais organ

Gabriel R F 10 Oct 12, 2022
Design and build a wrapper for the Open Weather API current weather data service

Design and build a wrapper for the Open Weather API current weather data service that returns a city's temperature, with caching, also allowing for the temperature of the latest queried cities that a

Duan Rafael Ribeiro 1 Jun 27, 2022
A Telegram Music Tag Editor Bot that can remove almost all usernames in the music tags and add own username instead.

Music Tag Editor Bot A Telegram Music Tag Editor Bot that can remove almost all usernames in the music tags and add own username instead. It can also

14 Oct 21, 2022
Web3 Pancakeswap Sniper & honeypot detector Take Profit/StopLose bot written in python3, For ANDROID WIN MAC & LINUX

Pancakeswap BSC Sniper Bot web3 with honeypot detector (ANDROID WINDOWS MAC LINUX) First SNIPER BOT for ANDROID with honeypot detector Web3 Pancakeswa

HYDRA 1 Dec 23, 2021
Python notebook allows send bulk whatsapp messages to contacts (not necessarily saved) using an excel file and the selenium package. It also produces a final report on the sending status of the messages.

WhatsApp messages bulk sending 📩 Este notebook (python) te permite enviar mensajes masivos de WhatsApp. El insumo principal es una hoja excel que con

Braulio Arteaga Lescano 8 Sep 15, 2022
RaidBot for WhatsApp

WhatsappRaid Скрипт подготовлен специально для сайта https://pysoc.ru и Ютуб канала PyPro Русский Простой спам бот для WhatsApp на Python3. Работает с

2 May 12, 2022
Dashbot is an application for showing the trade in U.S. Trade Market

Dashbot is an application for showing the trade in U.S. Trade Market (e.g., 4:00am to 8:00pm Eastern Time for the US market using Intraday data using Mercury..

Ahmed Nabil 2 Jan 27, 2022
ANKIT-OS/STYLISH-TEXT is a special repository. Its Is A Telegram Bot Which Can Translate Your Text Into 100+ Language

🔥 ᴳᴼᴼᴳᴸᴱ⁻ᵀᴿᴬᴺᔆᴸᴬᵀᴱᴿ 🔥 The owner would not be responsible for any kind of bans due to the bot. • ⚡ INSTALLING ⚡ • • 🛠️ Lᴀɴɢᴜᴀɢᴇs Aɴᴅ Tᴏᴏʟs 🔰 • If

ANKIT KUMAR 1 Dec 23, 2021
Add Me To Your Group Enjoy With Me. Pyrogram bot. https://t.me/TamilSupport

SongPlayRoBot 3X Fast Telethon Based Bot ⚜ Open Source Bot 👨🏻‍💻 Demo : SongPlayRoBot 💃🏻 Easy To Deploy 🤗 Click Below Image to Deploy DEPLOY Grou

IMVETRI 850 Dec 30, 2022
The public discord bot, created by: primitt, further developed by: duino-coin team.

Duino Stats Mini A public Duino-Stats Discord bot. Click this link to invite the bot to your server. License Duino Stats Mini distributed under the MI

primboi 8 Mar 14, 2022
Example app to be deployed to AWS as an API Gateway / Lambda Stack

Disclaimer I won't answer issues or emails regarding the project anymore. The project is old and not maintained anymore. I'm not sure if it still work

Ben 123 Jan 01, 2023
(@Tablada32BOT is my bot in twitter) This is a simple bot, its main and only function is to reply to tweets where they mention their bot with their @

Remember If you are going to host your twitter bot on a page where they can read your code, I recommend that you create an .env file and put your twit

3 Jun 04, 2021
tgEasy's Official Assistant Bot and Example Bot

tgEasy Assistant The assistant bot that helps people with tgEasy directly on Telegram. This repository contains the source code of @tgEasyRobot and th

Divide Projects™ 4 Dec 26, 2022
OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)

OpenAPI Generator Master (5.3.1): 5.4.x (5.4.x): 6.0.x (6.0.x): ⭐ ⭐ ⭐ If you would like to contribute, please refer to guidelines and a list of open t

OpenAPI Tools 14.8k Jan 04, 2023
Live Weather Updates using Flask and OpenWeather

AuraX Live Weather Updates using Flask and OpenWeather Installation To setup this project on your local machine, first clone this repository and insta

Ayush Gupta 3 Nov 02, 2021
=>|<= the MsgRoom bot for Windows 96

=|= bot A MsgRoom bot in Python 3 for Windows96.net. The bot joins as =|=, if parameter name_lasts is not true and default_name is =|=. The full

Larry Holst 2 Jun 07, 2022
DeFi wallet on Chia Network.

DeFi wallet on Chia Network.

GobyWallet 21 Aug 12, 2022
Mixcloud API wrapper for Python and Async IO

aiomixcloud Mixcloud API wrapper for Python and Async IO aiomixcloud is a wrapper library for the HTTP API of Mixcloud. It supports asynchronous opera

Aristotelis Mikropoulos 26 Dec 31, 2022
Ghost-toolbox - Ghost's official Discord raid tool

Ghost Toolbox Ghost's official Discord raid tool. How to use Clone this repo int

G H Ø S T 10 Oct 31, 2022