{"id":26743099,"url":"https://github.com/meissadia/hoopscrape","last_synced_at":"2025-08-09T20:20:33.883Z","repository":{"id":56876624,"uuid":"65224882","full_name":"meissadia/hoopscrape","owner":"meissadia","description":"HoopScrape: Ruby API for NBA data","archived":false,"fork":false,"pushed_at":"2018-08-07T07:30:11.000Z","size":100,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-14T01:47:42.215Z","etag":null,"topics":["api","basketball","basketball-stats","nba-data","ruby"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meissadia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-08T17:31:19.000Z","updated_at":"2018-08-27T15:59:14.000Z","dependencies_parsed_at":"2022-08-20T11:30:50.088Z","dependency_job_id":null,"html_url":"https://github.com/meissadia/hoopscrape","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meissadia%2Fhoopscrape","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meissadia%2Fhoopscrape/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meissadia%2Fhoopscrape/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meissadia%2Fhoopscrape/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meissadia","download_url":"https://codeload.github.com/meissadia/hoopscrape/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245984556,"owners_count":20704794,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","basketball","basketball-stats","nba-data","ruby"],"created_at":"2025-03-28T06:45:34.132Z","updated_at":"2025-03-28T06:45:34.921Z","avatar_url":"https://github.com/meissadia.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg style='width:100%' src='./readme/logo-hoopscrape.png' /\u003e\nhoopscrape is not associated with ESPN or the NBA   \n\n[![Gem Version](https://badge.fury.io/rb/hoopscrape.svg)](https://badge.fury.io/rb/hoopscrape)\n[![Code Climate](https://codeclimate.com/github/meissadia/hoopscrape/badges/gpa.svg)](https://codeclimate.com/github/meissadia/hoopscrape)\n[![Build Status](https://travis-ci.org/meissadia/hoopscrape.svg?branch=master)](https://travis-ci.org/meissadia/hoopscrape)\n[![Test Coverage](https://codeclimate.com/github/meissadia/hoopscrape/badges/coverage.svg)](https://codeclimate.com/github/meissadia/hoopscrape/coverage)\n\n## Table of Contents\n+ [Introduction](#introduction)\n+ [Installation](#installation)\n\t+ [Rails](#rails)\n\t+ [Manual](#manual)\n+ [Arrays, Hashes or Structs](#arrays-hashes-or-structs)\n\t+ [Working With Multiple Formats](#working-with-multiple-formats)\n\t\t+ [Default format](#default-format)\n\t\t+ [Same data using Hashes](#same-data-using-hashes)\n\t\t+ [Same data using Structs](#same-data-using-structs)\n\t+ [Customize Field Names for Hash and Struct Conversion](#customize-field-names-for-hash-and-struct-conversion)\n\t\t+ [Default As Template](#default-as-template)\n\t\t+ [Overwrite Default](#overwrite-default)\n+ [Working with Navigators](#working-with-navigators)\n\t+ [Navigator Methods](#navigator-methods)\n+ [Data Access](#data-access)\n\t+ [NBA Team List](#nba-team-list)\n\t+ [Boxscore](#boxscore)\n\t\t+ [Player Data](#player-data)\n\t\t+ [Team Data](#team-data)\n\t+ [Roster](#roster)\n\t+ [Player](#player)\n\t+ [Schedule](#schedule)\n\t\t+ [Past Schedule Games as Structs](#past-schedule-games-as-structs)\n\t\t+ [Future Schedule Games as Structs](#future-schedule-games-as-structs)\n\t\t+ [Select a specific Season Type](#select-a-specific-season-type)\n\t\t+ [Select Historic Schedule data](#select-historic-schedule-data)\n+ [Chaining it all together](#chaining-it-all-together)\n+ [Documentation](#documentation)\n+ [Requirements](#requirements)\n\t+ [Ruby version](#ruby-version)\n\t+ [Dependencies](#dependencies)\n+ [Testing](#testing)\n+ [Contributing](#contributing)\n\n\n## Introduction\nThe hoopscrape Ruby gem is a scraper for NBA data.\nIt provides a number of ways to simplify data interaction, including :\n+ Structs - Intuitively access data via dot notation.\n+ Hashes - Pass data directly to ActiveRecord CRUD methods for easy database interaction.\n+ String arrays - Raw data for you to manipulate as you see fit.\n\nVersion 1.1\n+ Fixed security vulnerabilities with Nokogiri and Rubocop.  Unfortunately, this means HoopScrape now requires Ruby \u003e= 2.1.0\n+ Updated test suite.\n\n+ Please report any [issues] you encounter!\n\n\n## Installation\n#### Rails\nIn your application\u0026#39;s Gemfile, include :\n\n```\ngem 'hoopscrape'\n```\nIn your project dir, execute :\n\n```\n$ bundle install\n```\n#### Manual\n```\n$ gem install hoopscrape\n```\n## Arrays, Hashes or Structs\nIf 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].\n\n```ruby\n  require 'hoopscrape'\n  hs   = HoopScrape.new                      # String Arrays\n  hs_h = HoopScrape.new(format: :to_hashes)  # Hash Arrays\n  hs_s = HoopScrape.new(format: :to_structs) # Struct Arrays\n```\n#### Working With Multiple Formats\nArrays can easily be converted to Hashes or Structs\n\n##### Default format\n```ruby\nhs    = HoopScrape.new\nbs    = es.boxscore(400828991)   # Return an NbaBoxscore object\nstats = bs.homePlayers           # Returns a multidimensional array of Home Player stats\nstats[4][2]                      # Player Name   # =\u003e 'R. Hood'\nstats[4][20]                     # Player Points # =\u003e '30'\n```\n##### Same data using Hashes\n```ruby\ns_hashes = stats.to_hashes       # Returns array of Hashes\ns_hashes[4][:name]               # Player Name   # =\u003e 'R. Hood'\ns_hashes[4][:points]             # Player Points # =\u003e '30'\n```\n##### Same data using Structs\n```ruby\ns_structs = stats.to_structs     # Returns array of Structs\ns_structs[4].name                # Player Name   # =\u003e 'R. Hood'\ns_structs[4].points              # Player Points # =\u003e '30'\n```\n#### Customize Field Names for Hash and Struct Conversion\nThe [Array#to_hashes] and [Array#to_structs] methods can be passed an array of Symbols\nto use in place of the default field names.\n\n```ruby\nteam_list   = HoopScrape.teamList\nteam_list_s = t.to_structs([:abbrev, :long_team_name, :div, :conf]) # New Field Names\nteam_list_s.last.long_team_name    # =\u003e 'Utah Jazz'\n```\nDefaults are defined in the [SymbolDefaults] module.\nYou can overwrite them or use them as templates, replacing individual symbols using\nthe [Array#change_sym!] method.\n\n##### Default As Template\n`Safe method`\n\n```ruby\nmy_names = S_ROSTER.dup.change_sym!(:p_name, :full_name).change_sym!(:salary, :crazy_money)\nplayers  = HoopScrape.roster('CLE').players.to_structs(my_names)\nplayers[3].full_name    # =\u003e 'LeBron James'\nplayers[3].crazy_money  # =\u003e '22970500'\n```\n##### Overwrite Default\n`Note: Changes affect all instances of hoopscrape`\n\n```ruby\nS_TEAM    # =\u003e [:team,  :name, :division, :conference]\nS_TEAM.replace [:short, :long, :div, :conf]\nt = HoopScrape.teamList.to_structs\n\nt.first.short # =\u003e 'BOS'\nt.first.long  # =\u003e 'Boston Celtics'\n```\n## Working with Navigators\nTable 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.\n\nNote: Data converted using [Array#to_structs] or [Array#to_hashes] is not wrapped in a Navigator.\n\n### Navigator Methods\n```ruby\n# \u003cNavigator\u003e A Navigator for Home Player Stats Table\nnavigator = HoopScrape.boxscore(400878158).homePlayers\n\nnavigator[]      # Array\u003cObject\u003e Returns the underlying Array of the Navigator\nnavigator[5]     # \u003cObject\u003e 6th row of data\nnavigator.size   # \u003cFixnum\u003e Number of table rows\nnavigator.first  # \u003cObject\u003e Access the first data row\nnavigator.last   # \u003cObject\u003e Access the last data row\nnavigator.next   # \u003cObject\u003e Access the next data row     (nil if there is no more data)\nnavigator.curr   # \u003cObject\u003e Access the current data row  (nil at initialization)\nnavigator.prev   # \u003cObject\u003e Access the previous data row (nil if there is no more data)\n```\n## Data Access\n### NBA Team List\n```ruby\nhs        = HoopScrape.new\nteam_list = es.teamList      # multidimensional array of Team info\nteam_list.last               # =\u003e ['UTA', 'Utah Jazz', 'Northwest', 'Western']\nteam_list.last[0]            # =\u003e 'UTA'\nteam_list.last[1]            # =\u003e 'Utah Jazz'\nteam_list.last[2]            # =\u003e 'Northwest'\nteam_list.last[3]            # =\u003e 'Western'\n```\n### Boxscore\nBoxscore #homePlayers, #awayPlayers return a [Navigator]\n\n```ruby\nhs    = HoopScrape.new(format: :to_structs)\nbs    = es.boxscore(400875892)   # Return an NbaBoxscore object\n\nbs.id                 # \u003cString\u003e Boxscore ID    # =\u003e '400875892'\nbs.gameDate           # \u003cString\u003e Game DateTime  # =\u003e '2016-05-07 00:00:00'\n\nbs.homeName           # \u003cString\u003e Full Team Name\nbs.homeScore          # \u003cString\u003e Team Score\nbs.homeTotals         # \u003cObject\u003e Access the cumulative team totals\nbs.homePlayers        # \u003cNavigator\u003e A Navigator for Home Player Stats Table\n\nbs.awayName           # \u003cString\u003e Full Team Name\nbs.awayScore          # \u003cString\u003e Team Score\nbs.awayTotals         # \u003cObject\u003e Access the cumulative team totals\nbs.awayPlayers        # \u003cNavigator\u003e A Navigator for Home Player Stats Table\n```\n##### Player Data\n```ruby\nwade = bs.homePlayers[4] # \u003cObject\u003e of data for Row 5\n\nwade.team       # \u003cString\u003e Team ID          # =\u003e 'MIA'\nwade.id         # \u003cString\u003e Player ID        # =\u003e '1987'\nwade.name       # \u003cString\u003e Short Name       # =\u003e 'D. Wade'\nwade.position   # \u003cString\u003e Position         # =\u003e 'SG'\nwade.minutes    # \u003cString\u003e Minutes          # =\u003e '36'\nwade.fgm        # \u003cString\u003e Shots Made       # =\u003e '13'\nwade.fga        # \u003cString\u003e Shots Attempted  # =\u003e '25'\nwade.tpm        # \u003cString\u003e 3P Made          # =\u003e '4'\nwade.tpa        # \u003cString\u003e 3P Attempted     # =\u003e '6'\nwade.ftm        # \u003cString\u003e Freethrows Made  # =\u003e '8'\nwade.fta        # \u003cString\u003e Freethrows Att.  # =\u003e '8'\nwade.oreb       # \u003cString\u003e Offensive Reb.   # =\u003e '1'\nwade.dreb       # \u003cString\u003e Defensive Reb.   # =\u003e '7'\nwade.rebounds   # \u003cString\u003e Total Rebounds   # =\u003e '8'\nwade.assists    # \u003cString\u003e Assists          # =\u003e '4'\nwade.steals     # \u003cString\u003e Steals           # =\u003e '0'\nwade.blocks     # \u003cString\u003e Blocks           # =\u003e '0'\nwade.tos        # \u003cString\u003e Turnovers        # =\u003e '4'\nwade.fouls      # \u003cString\u003e Personal Fouls   # =\u003e '1'\nwade.plusminus  # \u003cString\u003e Plus/Minus       # =\u003e '-8'\nwade.points     # \u003cString\u003e Points           # =\u003e '38'\nwade.starter    # \u003cString\u003e Starter?         # =\u003e 'true'\n```\n##### Team Data\n```ruby\nmiami = bs.homeTotals   # \u003cObject\u003e Access the team totals\nmiami.team\nmiami.fgm\nmiami.fga\nmiami.tpm\nmiami.tpa\nmiami.ftm\nmiami.fta\nmiami.oreb\nmiami.dreb\nmiami.rebounds\nmiami.assists\nmiami.steals\nmiami.blocks\nmiami.turnovers\nmiami.fouls\nmiami.points\n```\n### Roster\nRoster #players is a [Navigator].\n\n```ruby\nroster  = es.roster('UTA')\nr_hash  = es.roster('UTA', format: :to_hashes)  # Pre-format players data\nplayers = roster.players                        # Returns multidimensional array of Roster info\ncoach   = roster.coach                          # Coach Name # =\u003e 'Quinn Snyder'\n\n# Roster as an array of objects\nplayers = players.to_structs   # Returns array of Structs\n\nplayers[2].team                # Team ID          # =\u003e 'UTA'\nplayers[2].jersey              # Jersey Number    # =\u003e '11'\nplayers[2].name                # Name             # =\u003e 'Alec Burks'\nplayers[2].id                  # ID               # =\u003e '6429'\nplayers[2].position            # Position         # =\u003e 'SG'\nplayers[2].age                 # Age              # =\u003e '24'\nplayers[2].height_ft           # Height (ft)      # =\u003e '6'\nplayers[2].height_in           # Height (in)      # =\u003e '6'\nplayers[2].salary              # Salary           # =\u003e '9463484'\nplayers[2].weight              # Weight           # =\u003e '214'\nplayers[2].college             # College          # =\u003e 'Colorado'\nplayers[2].salary              # Salary           # =\u003e '9463484'\n```\n### Player\n```ruby\nplayer = es.player(2991473) # Returns an NbaPlayer object\nplayer.name                 #=\u003e \"Anthony Bennett\"\nplayer.age                  #=\u003e \"23\"\nplayer.weight               #=\u003e \"245\"\nplayer.college              #=\u003e \"UNLV\"\nplayer.height_ft            #=\u003e \"6\"\nplayer.height_in            #=\u003e \"8\"\n```\n### Schedule\nSchedule #allGames, #pastGames, #futureGames return a [Navigator]\n\n```ruby\nschedule = es.schedule('UTA')                      # Gets latest available year and season type data\nschedule = es.schedule('LAC', format: :to_structs) # Pre-format data (:to_hashes / :to_structs)\nschedule = es.schedule('SAS', year: 2005)          # Gets historical data for season ending in 2005\nschedule = es.schedule('POR', season: 1)           # Get specific season type (1 Pre/ 2 Regular/3 Post)\n\nschedule.nextGame                            # \u003cObject\u003e Next unplayed game info\nschedule.lastGame                            # \u003cObject\u003e Previously completed game info\nschedule.nextTeamId                          # \u003cString\u003e Team ID of next opponent # =\u003e 'OKC'\nschedule.nextGameId                          # \u003cFixnum\u003e Index of next unplayed game\n\nschedule.pastGames[]                         # Completed Games : [Object]\nschedule.futureGames[]                       # Upcoming Games  : [Object]\n\npast     = schedule.pastGames                # Completed Games : \u003cNavigator\u003e\nfuture   = schedule.futureGames              # Upcoming Games  : \u003cNavigator\u003e\n```\n##### Past Schedule Games as Structs\n```ruby\npast = schedule.pastGames # Completed Games : \u003cNavigator\u003e\ngame = past.next          # \u003cObject\u003e Game info\ngame.team                 # Team ID\ngame.game_num             # Game # in Season\ngame.date                 # Game Date\ngame.home                 # Home?\ngame.opponent             # Opponent ID\ngame.win                  # Win?\ngame.team_score           # Team Score\ngame.opp_score            # Opponent Score\ngame.boxscore_id          # Boxscore ID\ngame.wins                 # Team Win Count\ngame.losses               # Team Loss Count\ngame.datetime             # Game DateTime\ngame.season_type          # Season Type\n```\n##### Future Schedule Games as Structs\n```ruby\nfuture = schedule.futureGames  # Upcoming Games  : \u003cNavigator\u003e\ngame   = future.next           # \u003cObject\u003e Game info\ngame.team                      # Team ID\ngame.game_num                  # Game # in Season\ngame.date                      # Game Date\ngame.home                      # Home?\ngame.opponent                  # Opponent ID\ngame.time                      # Game Time\ngame.win                       # Win?\ngame.tv                        # Game on TV?\ngame.opp_score                 # Opponent Score\ngame.datetime                  # Game DateTime\ngame.season_type               # Season Type\n```\n##### Select a specific Season Type\n```ruby\npreseason = es.schedule('BOS', season: 1)   # Get Preseason schedule\nregular   = es.schedule('NYK', season: 2)   # Get Regular schedule\nplayoffs  = es.schedule('OKC', season: 3)   # Get Playoff schedule\n```\n##### Select Historic Schedule data\nThe year parameter should correspond to the year in which the season ended.\n\n```ruby\nschedule = es.schedule('SAS', year: 2005)    # Data for 2004-05 Season\n```\n## Chaining it all together\n```ruby\n# Get a Boxscore from a past game\nHoopScrape.schedule('OKC', season: 2).allGames[42].boxscore(:to_structs).awayPlayers.first.name\n\n# Get a Roster from a Team ID\nHoopScrape.boxscore(400827977).homeTotals[0].roster(:to_hashes).players.first[:name]\n\n'cle'.roster(:to_structs).players.next.position\n\n# Get a Schedule from a Team ID\nHoopScrape.teamList.last[0].schedule(:to_hashes).lastGame.boxscore\n\n'gsw'.schedule(:to_structs).lastGame.boxscore\n```\n## Documentation\nAvailable on [RubyDoc.info] or locally:\n\n```\n$ yard doc\n$ yard server\n```\n## Requirements\n### Ruby version\n\n- Ruby \u0026gt;= 1.9.3\n\n### Dependencies\n\n- Nokogiri ~\u003e 1.6\n- Rake\n- minitest\n\n## Testing\n```\n$ rake\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/meissadia/hoopscrape\n\u003cbr\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\u0026copy; 2016 Meissa Dia\n\n[CHANGELOG]: ./CHANGELOG.md\n[RubyDoc.info]: http://www.rubydoc.info/gems/hoopscrape/1.0.0\n[Navigator]: http://www.rubydoc.info/gems/hoopscrape/1.0.0/Navigator\n[Array#to_structs]: http://www.rubydoc.info/gems/hoopscrape/1.0.0/Array#to_structs-instance_method\n[Array#to_hashes]: http://www.rubydoc.info/gems/hoopscrape/1.0.0/Array#to_hashes-instance_method\n[Array#change_sym!]: http://www.rubydoc.info/gems/hoopscrape/1.0.0/Array#change_sym%21-instance_method\n[SymbolDefaults]: ./lib/hoopscrape/SymbolDefaults.rb\n[issues]: https://github.com/meissadia/hoopscrape/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeissadia%2Fhoopscrape","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeissadia%2Fhoopscrape","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeissadia%2Fhoopscrape/lists"}