seemethere / nba_py

Python client for NBA statistics located at stats.nba.com
BSD 3-Clause "New" or "Revised" License
1.05k stars 255 forks source link

test returns 400 error #10

Closed Peppershaker closed 8 years ago

Peppershaker commented 8 years ago

Hey man, really appreciate your work, trying to run the best bs = game.Boxscore('0041400122') print bs.game_summary()

keeps on returning 400 error, i imported game from nba_py, any idea?

HTTPError Traceback (most recent call last)

in () ----> 1 bs = game.Boxscore('0041400122') 2 print bs.game_summary() C:\Anaconda2\lib\site-packages\nba_py\game.pyc in **init**(self, game_id, range_type, start_period, end_period, start_range, end_range) 19 'EndPeriod': end_period, 20 'StartRange': start_range, ---> 21 'EndRange': end_range}) 22 23 def game_summary(self): C:\Anaconda2\lib\site-packages\nba_py__init__.pyc in _get_json(endpoint, params) 40 _get = get(BASE_URL.format(endpoint=endpoint), params=params) 41 # print _get.url ---> 42 _get.raise_for_status() 43 return _get.json() 44 C:\Anaconda2\lib\site-packages\requests\models.pyc in raise_for_status(self) 838 839 if http_error_msg: --> 840 raise HTTPError(http_error_msg, response=self) 841 842 def close(self): HTTPError: 400 Client Error: Bad Request for url: http://stats.nba.com/stats/boxscore/?GameID=0041400122&RangeType=0&StartPeriod=0&StartRange=0&EndPeriod=0&EndRange=0
jorgegil96 commented 8 years ago

This is bad.
HTTPError: 400 is generated by the server, which means stats.nba.com is blocking non-browser requests.
I haven't used nba_py (the endpoint documentation is great though) but from what i see in the code @seemethere is using the requests library.

A couple of days ago i encountered this same error in one of my scripts and the solution was to trick the server into thinking the request is being made by a browser (in my case, firefox).
I'm using urllib instead of requests though, i don't know if requests allows this. I'll leave a small piece of code, it might be helpful to @seemethere .

import json
from urllib.request import FancyURLopener

class MyOpener(FancyURLopener):
    version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11';

myopener = MyOpener();

standingsUrl = "http://stats.nba.com/stats/playoffpicture?LeagueID=00&SeasonID=22015"
response = myopener.open(recordUrl).read()
jsonData = json.loads(response.decode('utf-8'))
ghost commented 8 years ago

Yup, stats.nba.com seems to be blocking non-browser requests. But there's an easy enough fix if @seemethere is using the requests library, or for anyone else trying to access the API with requests.

I encountered the same problem yesterday when I first started trying to use the nba_py so i decided to try accessing the API directly. When using requests.get() you simply pass a valid browser user-agent string to the headers argument in requests.get(). For example:

import requests
import pandas as pd
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0',}
url = "http://stats.nba.com/stats/scoreboardV2?DayOffset=0&LeagueID=00&gameDate=01%2F26%2F2016"
response = requests.get(url, headers=headers)
scoreboard = response.json()['resultSets'][0]['rowSet']
scoreboard_frame = pd.DataFrame(scoreboard, columns = response.json()['resultSets'][0]['headers']
jorgegil96 commented 8 years ago

@jackam0 Great! I didn't know how to do it with requests, it seems a bit silly to block non-browser requests but browser requests open though. I hope it's not a step towards requiring API credentials...

seemethere commented 8 years ago

Fixed with https://github.com/seemethere/nba_py/commit/338654ea586b30ad2d01792ba864b174d0ab7cf3

kevinjesse commented 8 years ago

boxscore is giving a 400 for examples.

HTTPError: 400 Client Error: Bad Request for url: http://stats.nba.com/stats/boxscore/?GameID=0041400122&RangeType=0&StartPeriod=0&StartRange=0&EndPeriod=0&EndRange=0

I changed my headers to reflect the working browser results but to no avail.

seemethere commented 8 years ago

@kevinjesse when you do this game.Boxscore('0041400122') make sure that 0041400122 is a string and not an int. If it is passed as an int then it gets converted to 8781906. Changing it to a string in the call solved the issue for me.