Created
April 14, 2015 09:51
-
-
Save Bl3f/77d994f864215f721919 to your computer and use it in GitHub Desktop.
Python wrapper for SearchMetrics API v1. Need Oauth.
This file contains 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
import datetime | |
import itertools | |
import oauth2 as oauth | |
import requests | |
import time | |
class SearchMetricAPIError(Exception): | |
pass | |
class SearchMetricsAPI: | |
""" | |
SearchMetrics wrapper class for generic API. Use v1 version of the API. | |
""" | |
base_url = "http://api.searchmetrics.com/v1" | |
"Base URL of the API" | |
def __init__(self, consumer_key, consumer_secret, debug=False): | |
""" | |
API wrapper constructor | |
:param consumer_key: API consumer key (to find in your account) | |
:type consumer_key: str | |
:param consumer_secret: API consumer secret (to find in your account) | |
:type consumer_secret: str | |
:param debug: Debug mode to not paginate and save credits | |
:type debug: bool | |
""" | |
# Initialize the consumer credentials | |
self.consumer_key = consumer_key | |
self.consumer_secret = consumer_secret | |
# If we run in debug mode to economize credits | |
self.debug = debug | |
# SM API need an empty Token | |
self.token = oauth.Token(key="", secret="") | |
# Build a consumer with the pair (key, secret) | |
self.consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) | |
def make_request(self, service, get_params={}): | |
""" | |
Method to make the request on the SM API. | |
:param service: API endpoint service to request (e.g. ProjectOrganicGetListRankingsHistoric) | |
:type service: str | |
:param get_params: GET parameters for the API extraction like an classic GET extract | |
:type get_params: dict | |
:return: python object representing the data, usually a list | |
:rtype list | |
""" | |
# If .json is not in the service we add '.json' at the end to concatenate this at this and of the requested URL | |
if '.json' not in service: | |
service += '.json' | |
url = '/'.join([self.base_url, service]) | |
# Limit of results returned by the API to handle pagination | |
limit = int(get_params.get('limit')) | |
# Get the offset for the pagination | |
offset = int(get_params.get('offset', 0)) | |
# List of all data returned by the API. When we paginate all the data append in this list. | |
# It's the list returned by the function | |
all_data = [] | |
# Initialize results list and loop broker True to enter in the loop | |
results = [] | |
first_loop = True | |
while len(results) == limit or first_loop: | |
# loop broker" | |
first_loop = False | |
# Build params with oauth data included | |
all_params = self.build_params(get_params) | |
# Update the params with the offset to paginate | |
all_params.update({ | |
"offset": offset, | |
}) | |
# URL with GET parameters to request to have the data | |
request_url = self.get_url(url, all_params) | |
# data returned by the API (python object list and dict combined) | |
request = requests.get(request_url) | |
# dump data returned by the API | |
self.dump_data(service, all_params, request) | |
# transform raw data to structured python object | |
results = request.json() | |
if request.status_code != 200: | |
raise SearchMetricAPIError(results.get(u'error_info').get(u'error_message')) | |
# Append data requested to all_data | |
all_data.append(results) | |
# Increment the offset | |
offset += limit | |
if self.debug: | |
break | |
return list(itertools.chain(*all_data)) | |
def get_url(self, url, params): | |
""" | |
Build Oauth v1 Request and return the URL of the data needed. Use standard signature HMAC_SHA1. | |
:param url: url of API endpoint | |
:type url: str | |
:param params: all params (included oauth headers and extract filters) | |
:type params: dict | |
:return: URL of API ressource with oauth API information | |
:rtype: str | |
""" | |
req = oauth.Request(method="GET", url=url, parameters=params) | |
signature_method = oauth.SignatureMethod_HMAC_SHA1() | |
req.sign_request(signature_method, self.consumer, self.token) | |
return req.to_url() | |
def build_params(self, get_params): | |
""" | |
Build Oauth and concatenate this to GET params to filter the data on the API endpoint. | |
:param get_params: GET parameters to filter the data | |
:type get_params: dict | |
:return: all API params | |
:rtype: dict | |
""" | |
params = { | |
# SM API use Oauth version 1 | |
'oauth_version': "1.0", | |
# Need to generate a nonce | |
'oauth_nonce': oauth.generate_nonce(), | |
# ... and a timestamp | |
'oauth_timestamp': int(time.time()), | |
'oauth_token': self.token.key, | |
'oauth_consumer_key': self.consumer.key, | |
} | |
return dict(params.items() + get_params.items()) | |
def dump_data(self, service, all_params, raw_data): | |
pass | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment