Last active
February 13, 2019 02:46
-
-
Save lebedov/8c3f33ebb55a67b732c1 to your computer and use it in GitHub Desktop.
Get LinkedIn access tokens without having to open a web browser.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Get LinkedIn OAuth1 access tokens without having to open a web browser. | |
Notes | |
----- | |
Based upon https://developer.linkedin.com/documents/getting-oauth-token-python | |
Assumes that the application API key, secret key, user name, and password are stored | |
in an a configuration file formatted as follows: | |
[Secrets] | |
API_KEY = WWWWWWWW | |
SECRET_KEY = XXXXXXXX | |
NAME = YYYYYYYY | |
PASSWORD = ZZZZZZZZ | |
""" | |
import re | |
import ConfigParser as cp | |
import oauth2 | |
import urlparse | |
import lxml.html | |
import mechanize | |
# Read secrets: | |
cfg_file = 'linkedin_config' | |
config = cp.ConfigParser() | |
config.read(cfg_file) | |
if not config.has_section('Secrets'): | |
raise RuntimeError('no secrets specified') | |
secrets = {} | |
for s in config.items('Secrets'): | |
secrets[s[0]] = s[1] | |
# Set up headless browser: | |
br = mechanize.Browser() | |
br.set_cookiejar(mechanize.CookieJar()) | |
br.set_handle_redirect(True) | |
br.set_handle_robots(False) | |
# Get request token: | |
consumer = oauth2.Consumer(secrets['api_key'], secrets['secret_key']) | |
client = oauth2.Client(consumer) | |
request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken' | |
response, content = client.request(request_token_url, 'POST') | |
if response['status'] != '200': | |
raise Exception('Invalid response') | |
request_token = dict(urlparse.parse_qsl(content)) | |
print 'request token: ', request_token['oauth_token'] | |
print 'request token secret: ', request_token['oauth_token_secret'] | |
# Use token to redirect to user login: | |
authorize_url = 'https://api.linkedin.com/uas/oauth/authorize' | |
redirect_url = '%s?oauth_token=%s' % (authorize_url, request_token['oauth_token']) | |
# Login with mechanize: | |
br.open(redirect_url) | |
br.select_form(nr=0) | |
br.form['session_key'] = secrets['username'] | |
br.form['session_password'] = secrets['password'] | |
br.submit() | |
html = br.response().read() | |
tree = lxml.html.fromstring(html) | |
oauth_verifier = tree.xpath('.//div[@class="access-code"]')[0].text_content() | |
# Use PIN to obtain access token: | |
token = oauth2.Token(request_token['oauth_token'], | |
request_token['oauth_token_secret']) | |
token.set_verifier(oauth_verifier) | |
access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken' | |
client = oauth2.Client(consumer, token) | |
response, content = client.request(access_token_url, 'POST') | |
access_token = dict(urlparse.parse_qsl(content)) | |
print 'access token: ', access_token['oauth_token'] | |
print 'access token secret: ', access_token['oauth_token_secret'] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Get LinkedIn OAuth2 access tokens without having to open a web browser. | |
Notes | |
----- | |
Requires `python-linkedin <https://github.com/ozgur/python-linkedin>`_. | |
Assumes that the application API key and secret key are stored in a | |
configuration file formatted as follows: | |
[Secrets] | |
API_KEY = WWWWWWWW | |
SECRET_KEY = XXXXXXXX | |
""" | |
import re | |
import ConfigParser as cp | |
import urlparse | |
from linkedin import linkedin | |
import mechanize | |
from mechanize import _response | |
from mechanize import _rfc3986 | |
# Read secrets: | |
cfg_file = 'linkedin_config' | |
config = cp.ConfigParser() | |
config.read(cfg_file) | |
if not config.has_section('Secrets'): | |
raise RuntimeError('no secrets specified') | |
secrets = {} | |
for s in config.items('Secrets'): | |
secrets[s[0]] = s[1] | |
class MyRedirectHandler(mechanize.HTTPRedirectHandler): | |
def http_error_302(self, req, fp, code, msg, headers): | |
# Code from mechanize._urllib2_fork.HTTPRedirectHandler: | |
if 'location' in headers: | |
newurl = headers.getheaders('location')[0] | |
elif 'uri' in headers: | |
newurl = headers.getheaders('uri')[0] | |
else: | |
return | |
newurl = _rfc3986.clean_url(newurl, "latin-1") | |
newurl = _rfc3986.urljoin(req.get_full_url(), newurl) | |
new = self.redirect_request(req, fp, code, msg, headers, newurl) | |
if new is None: | |
return | |
if hasattr(req, 'redirect_dict'): | |
visited = new.redirect_dict = req.redirect_dict | |
if (visited.get(newurl, 0) >= self.max_repeats or | |
len(visited) >= self.max_redirections): | |
raise HTTPError(req.get_full_url(), code, | |
self.inf_msg + msg, headers, fp) | |
else: | |
visited = new.redirect_dict = req.redirect_dict = {} | |
visited[newurl] = visited.get(newurl, 0) + 1 | |
fp.read() | |
fp.close() | |
# If the redirected URL doesn't match | |
new_url = new.get_full_url() | |
if not re.search('^http(?:s)?\:\/\/.*www\.linkedin\.com', new_url): | |
return _response.make_response('', headers.items(), new_url, 200, 'OK') | |
else: | |
return self.parent.open(new) | |
http_error_301 = http_error_303 = http_error_307 = http_error_302 | |
http_error_refresh = http_error_302 | |
# Set up headless browser: | |
br = mechanize.Browser() | |
br.set_cookiejar(mechanize.CookieJar()) | |
br.handler_classes['_redirect'] = MyRedirectHandler | |
br.set_handle_redirect(True) | |
br.set_handle_robots(False) | |
return_uri = 'http://localhost:9000' | |
auth = linkedin.LinkedInAuthentication(secrets['api_key'], | |
secrets['secret_key'], | |
return_uri, | |
linkedin.PERMISSIONS.enums.values()) | |
br.open(auth.authorization_url) | |
br.select_form(nr=0) | |
br.form['session_key'] = secrets['username'] | |
br.form['session_password'] = secrets['password'] | |
r = br.submit() | |
auth.authorization_code = urlparse.parse_qs(urlparse.urlsplit(r.geturl()).query)['code'] | |
access_token = auth.get_access_token() | |
app = linkedin.LinkedInApplication(token=access_token) |
Hello!
would it be possible to port these to python 3? It looks like at least the "mechanize" package does not work on python 3.
Thanks ,
Georges
Can you write this in python 3 with requests library please
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for your gist, it was very helpful :)
Just a fix for the oauth1 code credentials example:
[Secrets]
...
USERNAME = YYYYYYYY