Skip to content

meissadia/hoopscrape

Repository files navigation

hoopscrape is not associated with ESPN or the NBA

Gem Version Code Climate Build Status Test Coverage

Table of Contents

Introduction

The hoopscrape Ruby gem is a scraper for NBA data. It provides a number of ways to simplify data interaction, including :

  • Structs - Intuitively access data via dot notation.
  • Hashes - Pass data directly to ActiveRecord CRUD methods for easy database interaction.
  • String arrays - Raw data for you to manipulate as you see fit.

Version 1.1

  • Fixed security vulnerabilities with Nokogiri and Rubocop. Unfortunately, this means HoopScrape now requires Ruby >= 2.1.0

  • Updated test suite.

  • Please report any issues you encounter!

Installation

Rails

In your application's Gemfile, include :

gem 'hoopscrape'

In your project dir, execute :

$ bundle install

Manual

$ gem install hoopscrape

Arrays, Hashes or Structs

If you intend to work with a single format, you can specify it at initialization. When working with multiple formats you should start with the default and convert as necessary using Array#to_structs or Array#to_hashes.

  require 'hoopscrape'
  hs   = HoopScrape.new                      # String Arrays
  hs_h = HoopScrape.new(format: :to_hashes)  # Hash Arrays
  hs_s = HoopScrape.new(format: :to_structs) # Struct Arrays

Working With Multiple Formats

Arrays can easily be converted to Hashes or Structs

Default format
hs    = HoopScrape.new
bs    = es.boxscore(400828991)   # Return an NbaBoxscore object
stats = bs.homePlayers           # Returns a multidimensional array of Home Player stats
stats[4][2]                      # Player Name   # => 'R. Hood'
stats[4][20]                     # Player Points # => '30'
Same data using Hashes
s_hashes = stats.to_hashes       # Returns array of Hashes
s_hashes[4][:name]               # Player Name   # => 'R. Hood'
s_hashes[4][:points]             # Player Points # => '30'
Same data using Structs
s_structs = stats.to_structs     # Returns array of Structs
s_structs[4].name                # Player Name   # => 'R. Hood'
s_structs[4].points              # Player Points # => '30'

Customize Field Names for Hash and Struct Conversion

The Array#to_hashes and Array#to_structs methods can be passed an array of Symbols to use in place of the default field names.

team_list   = HoopScrape.teamList
team_list_s = t.to_structs([:abbrev, :long_team_name, :div, :conf]) # New Field Names
team_list_s.last.long_team_name    # => 'Utah Jazz'

Defaults are defined in the SymbolDefaults module. You can overwrite them or use them as templates, replacing individual symbols using the Array#change_sym! method.

Default As Template

Safe method

my_names = S_ROSTER.dup.change_sym!(:p_name, :full_name).change_sym!(:salary, :crazy_money)
players  = HoopScrape.roster('CLE').players.to_structs(my_names)
players[3].full_name    # => 'LeBron James'
players[3].crazy_money  # => '22970500'
Overwrite Default

Note: Changes affect all instances of hoopscrape

S_TEAM    # => [:team,  :name, :division, :conference]
S_TEAM.replace [:short, :long, :div, :conf]
t = HoopScrape.teamList.to_structs

t.first.short # => 'BOS'
t.first.long  # => 'Boston Celtics'

Working with Navigators

Table data is wrapped in a Navigator class which provides helper methods for moving through the table. The type of object the Navigator returns matches the format provided at hoopscrape instantiation.

Note: Data converted using Array#to_structs or Array#to_hashes is not wrapped in a Navigator.

Navigator Methods

# <Navigator> A Navigator for Home Player Stats Table
navigator = HoopScrape.boxscore(400878158).homePlayers

navigator[]      # Array<Object> Returns the underlying Array of the Navigator
navigator[5]     # <Object> 6th row of data
navigator.size   # <Fixnum> Number of table rows
navigator.first  # <Object> Access the first data row
navigator.last   # <Object> Access the last data row
navigator.next   # <Object> Access the next data row     (nil if there is no more data)
navigator.curr   # <Object> Access the current data row  (nil at initialization)
navigator.prev   # <Object> Access the previous data row (nil if there is no more data)

Data Access

NBA Team List

hs        = HoopScrape.new
team_list = es.teamList      # multidimensional array of Team info
team_list.last               # => ['UTA', 'Utah Jazz', 'Northwest', 'Western']
team_list.last[0]            # => 'UTA'
team_list.last[1]            # => 'Utah Jazz'
team_list.last[2]            # => 'Northwest'
team_list.last[3]            # => 'Western'

Boxscore

Boxscore #homePlayers, #awayPlayers return a Navigator

hs    = HoopScrape.new(format: :to_structs)
bs    = es.boxscore(400875892)   # Return an NbaBoxscore object

bs.id                 # <String> Boxscore ID    # => '400875892'
bs.gameDate           # <String> Game DateTime  # => '2016-05-07 00:00:00'

bs.homeName           # <String> Full Team Name
bs.homeScore          # <String> Team Score
bs.homeTotals         # <Object> Access the cumulative team totals
bs.homePlayers        # <Navigator> A Navigator for Home Player Stats Table

bs.awayName           # <String> Full Team Name
bs.awayScore          # <String> Team Score
bs.awayTotals         # <Object> Access the cumulative team totals
bs.awayPlayers        # <Navigator> A Navigator for Home Player Stats Table
Player Data
wade = bs.homePlayers[4] # <Object> of data for Row 5

wade.team       # <String> Team ID          # => 'MIA'
wade.id         # <String> Player ID        # => '1987'
wade.name       # <String> Short Name       # => 'D. Wade'
wade.position   # <String> Position         # => 'SG'
wade.minutes    # <String> Minutes          # => '36'
wade.fgm        # <String> Shots Made       # => '13'
wade.fga        # <String> Shots Attempted  # => '25'
wade.tpm        # <String> 3P Made          # => '4'
wade.tpa        # <String> 3P Attempted     # => '6'
wade.ftm        # <String> Freethrows Made  # => '8'
wade.fta        # <String> Freethrows Att.  # => '8'
wade.oreb       # <String> Offensive Reb.   # => '1'
wade.dreb       # <String> Defensive Reb.   # => '7'
wade.rebounds   # <String> Total Rebounds   # => '8'
wade.assists    # <String> Assists          # => '4'
wade.steals     # <String> Steals           # => '0'
wade.blocks     # <String> Blocks           # => '0'
wade.tos        # <String> Turnovers        # => '4'
wade.fouls      # <String> Personal Fouls   # => '1'
wade.plusminus  # <String> Plus/Minus       # => '-8'
wade.points     # <String> Points           # => '38'
wade.starter    # <String> Starter?         # => 'true'
Team Data
miami = bs.homeTotals   # <Object> Access the team totals
miami.team
miami.fgm
miami.fga
miami.tpm
miami.tpa
miami.ftm
miami.fta
miami.oreb
miami.dreb
miami.rebounds
miami.assists
miami.steals
miami.blocks
miami.turnovers
miami.fouls
miami.points

Roster

Roster #players is a Navigator.

roster  = es.roster('UTA')
r_hash  = es.roster('UTA', format: :to_hashes)  # Pre-format players data
players = roster.players                        # Returns multidimensional array of Roster info
coach   = roster.coach                          # Coach Name # => 'Quinn Snyder'

# Roster as an array of objects
players = players.to_structs   # Returns array of Structs

players[2].team                # Team ID          # => 'UTA'
players[2].jersey              # Jersey Number    # => '11'
players[2].name                # Name             # => 'Alec Burks'
players[2].id                  # ID               # => '6429'
players[2].position            # Position         # => 'SG'
players[2].age                 # Age              # => '24'
players[2].height_ft           # Height (ft)      # => '6'
players[2].height_in           # Height (in)      # => '6'
players[2].salary              # Salary           # => '9463484'
players[2].weight              # Weight           # => '214'
players[2].college             # College          # => 'Colorado'
players[2].salary              # Salary           # => '9463484'

Player

player = es.player(2991473) # Returns an NbaPlayer object
player.name                 #=> "Anthony Bennett"
player.age                  #=> "23"
player.weight               #=> "245"
player.college              #=> "UNLV"
player.height_ft            #=> "6"
player.height_in            #=> "8"

Schedule

Schedule #allGames, #pastGames, #futureGames return a Navigator

schedule = es.schedule('UTA')                      # Gets latest available year and season type data
schedule = es.schedule('LAC', format: :to_structs) # Pre-format data (:to_hashes / :to_structs)
schedule = es.schedule('SAS', year: 2005)          # Gets historical data for season ending in 2005
schedule = es.schedule('POR', season: 1)           # Get specific season type (1 Pre/ 2 Regular/3 Post)

schedule.nextGame                            # <Object> Next unplayed game info
schedule.lastGame                            # <Object> Previously completed game info
schedule.nextTeamId                          # <String> Team ID of next opponent # => 'OKC'
schedule.nextGameId                          # <Fixnum> Index of next unplayed game

schedule.pastGames[]                         # Completed Games : [Object]
schedule.futureGames[]                       # Upcoming Games  : [Object]

past     = schedule.pastGames                # Completed Games : <Navigator>
future   = schedule.futureGames              # Upcoming Games  : <Navigator>
Past Schedule Games as Structs
past = schedule.pastGames # Completed Games : <Navigator>
game = past.next          # <Object> Game info
game.team                 # Team ID
game.game_num             # Game # in Season
game.date                 # Game Date
game.home                 # Home?
game.opponent             # Opponent ID
game.win                  # Win?
game.team_score           # Team Score
game.opp_score            # Opponent Score
game.boxscore_id          # Boxscore ID
game.wins                 # Team Win Count
game.losses               # Team Loss Count
game.datetime             # Game DateTime
game.season_type          # Season Type
Future Schedule Games as Structs
future = schedule.futureGames  # Upcoming Games  : <Navigator>
game   = future.next           # <Object> Game info
game.team                      # Team ID
game.game_num                  # Game # in Season
game.date                      # Game Date
game.home                      # Home?
game.opponent                  # Opponent ID
game.time                      # Game Time
game.win                       # Win?
game.tv                        # Game on TV?
game.opp_score                 # Opponent Score
game.datetime                  # Game DateTime
game.season_type               # Season Type
Select a specific Season Type
preseason = es.schedule('BOS', season: 1)   # Get Preseason schedule
regular   = es.schedule('NYK', season: 2)   # Get Regular schedule
playoffs  = es.schedule('OKC', season: 3)   # Get Playoff schedule
Select Historic Schedule data

The year parameter should correspond to the year in which the season ended.

schedule = es.schedule('SAS', year: 2005)    # Data for 2004-05 Season

Chaining it all together

# Get a Boxscore from a past game
HoopScrape.schedule('OKC', season: 2).allGames[42].boxscore(:to_structs).awayPlayers.first.name

# Get a Roster from a Team ID
HoopScrape.boxscore(400827977).homeTotals[0].roster(:to_hashes).players.first[:name]

'cle'.roster(:to_structs).players.next.position

# Get a Schedule from a Team ID
HoopScrape.teamList.last[0].schedule(:to_hashes).lastGame.boxscore

'gsw'.schedule(:to_structs).lastGame.boxscore

Documentation

Available on RubyDoc.info or locally:

$ yard doc
$ yard server

Requirements

Ruby version

  • Ruby >= 1.9.3

Dependencies

  • Nokogiri ~> 1.6
  • Rake
  • minitest

Testing

$ rake

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/meissadia/hoopscrape


© 2016 Meissa Dia

Releases

No releases published

Packages

No packages published