Skip to content

Instantly share code, notes, and snippets.

@Bl3f
Created April 14, 2015 09:51
Show Gist options
  • Save Bl3f/77d994f864215f721919 to your computer and use it in GitHub Desktop.
Save Bl3f/77d994f864215f721919 to your computer and use it in GitHub Desktop.
Python wrapper for SearchMetrics API v1. Need Oauth.
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