3

My example code for accessing the Fantasy Sports API in Python

Here is the code I use in my Python desktop app to access the Yahoo Fantasy Sports API through OAuth. It's very unpolished. However, I've seen a lot of questions about using OAuth with Python. So I figured I'd post it in case it could help anyone:

https://github.com/mleveck/YHandler

by
22 Replies
  • Hi Matt,

    I was able to use your library to authenticate and download basic data. Thanks!

    However, I'm having trouble any time I add keys or filters to a data request I get oauth_problem="signature_invalid", even for the ubiquitous example in the API Docs: users;use_login=1

    So, I can pull the scoreboard for the current week, but not for, say, week 12. Could it have something to do with the semicolon?

    Have you dealt with or resolved this issue?

    Thanks for posting your code!

    1
  • I'm not sure why this works, but try making sure that your request URL ends with a '/' . When there are semi-colons, the Requests library sends items to the parameters portion of the request, rather than keeping them in the URL. Adding the '/' at the end seems to stop this.

    My personal opinion is that the API should in fact be based around sending a set of parameters, rather than constructing a particular URL, which would make it act more like other REST APIs and thus make standard libraries perform better without work-around hacks.

    1
  • Thanks, this was pretty much plug and play.

    0
  • I'm having issues just using your API to auth for basic data. I'm sure I'm using it wrong, but I don't really even know where to begin.

    0
  • See if this helps:

    instantiate a connection handler object using a CSV file with app tokens

    handler = YHandler('auth.csv')

    set a query string. Note, the base URL is not included

    querystring = 'team/304.l.41835.t.12/roster/players/percent_owned;type=date;date=%s/' % date

    call the api_req() method on the handler with the query string

    players_request = handler.api_req(querystring)

    players_request holds a html response object. Call players_request.text to get the xml body text

    0
  • Sorry for the huge text. I use a hash mark to indicate python comments. The forum interpreted it as HTML markdown, and thus turned those comment lines into HTML

    's

    0
  • Thanks for posting this code, but I seem to be running into a problem in the reg_user step. I set up my consumer key and secret in the auth.csv file, then after running

    response = requests.post(REQUEST_TOKEN_URL, params={'oauth_callback': CALLBACK_URL}, hooks={'pre_request': init_oauth_hook})

    if I recreate this manually, I get the following values in response

    response.text=u'oauth_problem=parameter_absent&oauth_parameters_absent=oauth_consumer_key,oauth_signature_method,oauth_signature,oauth_timestamp,oauth_nonce'

    response.reason='Authorization Required'

    Are additional parameters required in the request? If so, how do you set them (sorry I'm not familiar with oauth).

    Thanks again.

    0
  • I'm having the same issue as Mark. I know for a fact that the csv file is loading and the OAuthHook has my consumer key and secret loaded, but the post to get the request token fails with a 401 asking for oauth_consumer_key, oauth_signature_method, oauth_signature, oauth_timestamp, oauth_nonce.

    It's obviously telling me what is missing, but I'm not sure how much of this I should be populating, and how much is being handled by the requests-oauth library?

    I've managed to complete the reg_user process with the rauth library, but I cannot seem to figure out how to handle expired access tokens. There doesn't seem to be functionality for exchanging an existing expired token for a new one, only using request tokens to create an authenticated session...

    Any help at all would be appreciated!

    0
  • the newer versions of the requests library have removed most hooks… some changes need to be made to be compatible with requests 1.0+

    0
  • I was able to get the Yahoo Fantasy Sports API working by using the rauth library (https://github.com/litl/rauth) and the code below.

    from rauth import OAuth1Service

    yahoo = OAuth1Service( consumer_key=OAUTH_CONSUMER_KEY, consumer_secret=OAUTH_SHARED_SECRET, name='yahoo', access_token_url=access_token_url, authorize_url=authorize_url, request_token_url=request_token_url, base_url='https://api.login.yahoo.com/oauth/v2/') request_token, request_token_secret = yahoo.get_request_token(data = { 'oauth_callback': "http://example.com/callback/" }) print "Request Token:" print " - oauth_token = %s" % request_token print " - oauth_token_secret = %s" % request_token_secret print auth_url = yahoo.get_authorize_url(request_token) print 'Visit this URL in your browser: ' + auth_url pin = raw_input('Enter PIN from browser: ') session = yahoo.get_auth_session(request_token, request_token_secret, method='POST', data={'oauth_verifier': pin})

    -1
  • @kdub what are the access_token_url and authorize_url?

    I'm trying to generate a stats report for the 200 players that were in my league last year. Going to do some complex processing of all that... But in the meantime, how can I get started making queries?

    0
  • Hey all, sorry, I've been super busy with a new job. One Eye seems to be indicating that the library I use might have changed, or something. I won't have time to patch things up for awhile. However, if anyone submits a pull request with a fix, l'll happily accept it and update the code.

    0
  • @Michael Roch I used the values below

    request_token_url = "https://api.login.yahoo.com/oauth/v2/get_request_token" authorize_url = 'https://api.login.yahoo.com/oauth/v2/request_auth' access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token'

    1
  • @kdub,

    I was able to use your recommendation of rauth to enter a PIN (aka token verifier).

    However, am having problems getting the api_req() and call_api functions to work. Any help would be greatly appreciated.

    I am not sure how these functions should look with rauth instead of Matt's usage of OAuthHook. Here is what I am struggling with currently: def call_api(self, url, req_meth='GET', data=None, headers=None): oauth_hook = OAuthHook(self.authd['oauth_token'], self.authd['oauth_token_secret'], self.authd['consumer_key'], self.authd['consumer_secret'], header_auth=True) s = requests.Session() s.hooks={ 'pre_request' : oauth_hook } # s = requests.Session({ 'pre_request' : oauth_hook }) return s.get(url=url, data=data, headers=headers) # client = requests.session( {'pre_request':req_oauth_hook}) # return client.request(method=req_meth, url=url, data=data, headers=headers)

    0
  • Trying to post the code better:

    def call_api(self, url, req_meth='GET', data=None, headers=None):
            oauth_hook = OAuthHook(self.authd['oauth_token'], self.authd['oauth_token_secret'], self.authd['consumer_key'], self.authd['consumer_secret'], header_auth=True)
            s = requests.Session()
            s.hooks={ 'pre_request' : oauth_hook }
            # s = requests.Session({ 'pre_request' : oauth_hook })
            return s.get(url=url, data=data, headers=headers)
            # client = requests.session( {'pre_request':req_oauth_hook})
            # return client.request(method=req_meth, url=url, data=data, headers=headers)
    
    0
  • The pre-request hook was removed in version 1.0 of python-requests. You'll have to build a request object yourself, then pass it to the hook.

    oauth_hook = OAuthHook(self.access_tokens['oauth_token'], self.access_tokens['oauth_token_secret'], consumer_key=CONSUMER_KEY, consumer_secret=CONSUMER_SECRET, header_auth=True)
    request = requests.Request('GET', "<http://fantasysports.yahooapis.com/fantasy/v2/whatever>")
    request = oauth_hook(request)
    session = requests.session()
    response = session.send(request.prepare())
    
    0
  • Forum slightly mangled my code sample. sigh Let me try again.

    oauth_hook = OAuthHook(self.access_tokens['oauth_token'], self.access_tokens['oauth_token_secret'], consumer_key=CONSUMER_KEY, consumer_secret=CONSUMER_SECRET, header_auth=True)
    request = requests.Request('GET', api_url)
    request = oauth_hook(request)
    session = requests.session()
    response = session.send(request.prepare())
    

    I'm using https://github.com/maraujop/requests-oauth as per Matt's example code, but I bet the code will be similar when using rauth, as they both depend on python-requests.

    0
  • Indeed, python-requests 1.0 breaks YHandler. I attempted to create an updated version with the same API to cope with the changes. Instead of reqeusts-oauth, it uses a newer, requests-approved library called requests-oauthlib. Not confusing at all, right?

    The code is here <https://github.com/youse/YHandler>, and it works but with a big caveat. Even though a Yahoo oauth authorization lasts for ~25 years, each individual access token needs refreshing after one hour. My new YHandler fails to refresh the access token, since requests-oauthlib unfortunately doesn't handle the "oauth_session_handle" key used to refresh tokens. So you have to re-authorize from scratch after an hour if you use my code. I'm not happy with that at all, and if you aren't either, there are two main options left:

    1. Keep using the original YHandler with python-requests<1.0, along with the OAuthHook. Last I tried a few months ago, this still works and refreshes the tokens just fine. Installing and maintaining old versions of python libraries is easy with pip or similar.
    2. Use Rauth. This is what I did since my application depends on features of python-requests-1.0, and I wanted to be future-friendly besides. Unfortunately, the solution I cooked up isn't a clean module like YHandler, but is tightly coupled with my application code and wouldn't share well here. If there is interest, I could try to share some of the key Rauth-specific lines. (kdub has posted a good starting point, though)
    0
  • @kdub, @Bryan, I got rauth to work using kdub's code above. I have been unable to figure out how to refresh the tokens.

    Here is the line where I try to refresh the authorization:

    session = self.yahoo.get_session((access_token, access_token_secret))

    where,

    access_token = prior_session.access_token and

    access_token_secret = prior_session.access_token_secret

    I get this error with the above code: 'Please provide valid credentials. OAuth oauth_problem="signature_invalid", realm="yahooapis.com"'

    0
  • Nevermind, I got it working. The error was a spurious newline that I had after reading my stored access_token and access_token_secret.

    0
  • I didn't actually get the refresh working properly. Any tips would be appreciated.

    0
  • You can take a look at the code I use to see how to refresh the access token. It uses rauth.

    https://github.com/dkempiners/python-yahooapi/blob/master/yahooapi.py

    0

Recent Posts

in Fantasy Sports API