text: I don't have the time to commit to this project any more. Please get in contact with me if you want to help keep it alive.
  👨💼 Linkedin API for Python
  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.
  ⚠️ Python >= 3.6 required
  pip3 install linkedin-api~=2.0.0a
  from linkedin_api import Linkedin # Authenticate using any Linkedin account credentials api = Linkedin('reedhoffman@linkedin.com', '*******') # 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')
  For a complete reference documentation, see the documentation website.
  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.
  Learn how to find endpoints
  pipenv(optional)
  Create a
  .env config file. An example is provided in
  .env.example - you include at least all of the settings set there.
  Using pipenv...
  pipenv install --dev pipenv shell
  python -m pytest tests
  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:
  Please add more as you come across them.
  searchmethod. 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.
  Voyager endpoints look like this:
  Or, more clearly
  ___________________________________ _______________________________ | base path | resource | /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.
  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:
  view source
  command-f/search the page for some keyword in the data. This will exist inside of a
  <code> tag.
  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>
  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.
  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).
  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.
  This project may not be used for any of the following:
  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.
  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.