Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Roster endpoint #33

Open
fgblomqvist opened this issue Aug 24, 2017 · 11 comments
Open

Roster endpoint #33

fgblomqvist opened this issue Aug 24, 2017 · 11 comments

Comments

@fgblomqvist
Copy link

Is there a known endpoint for getting a team's roster (for future support)?

@irish1986
Copy link

irish1986 commented Aug 24, 2017

I wrote/adapted the following code as a simple standalone code to extract team's roster. I am still working a improving it but I am not "git-savvy" enough yet to make a PR to add this.

Maybe it will inspire some people here.

class InvalidPlayerRow(ValueError):
    pass

def _from_content_row(content_row, headers):
    data = {}
    for child, header in zip(content_row.children, headers):
        if header:
            # Special casing for name/pos
            if header == 'PLAYER, TEAM POS':
                player_name = list(child.children)[0].string.strip()
                if not player_name:
                    raise InvalidPlayerRow('Could not parse a player name')
                data['name'] = player_name
                pos = list(child.children)[1].split()
                if len(pos) == 1:
                    data[attr_lineup['TEAM']] = None
                    data[attr_lineup['POS']] = pos[0]
                elif len(pos) == 3:
                    data[attr_lineup['TEAM']] = pos[1]
                    data[attr_lineup['POS']] = pos[2]
                player_slot = list(child.children)[3].string.strip() # having some issue here
                data['slot'] = player_slot # having some issue with player slot
            else:
                # something doesn't work here, might be because the league isn't fully active
                #data[attr_lineup[header]] = child.string
                pass
    return data


def _get_headers(row):
    """Given a subheader in the player table, return a list of column names"""
    return [header.string for header in row.children]


def _get_players(soup):
    # Get all the rows in the player table
    table = soup.find('table', 'playerTableTable')
    rows = table.find_all('tr')
    players = []
    # Grab all the headers so we can match stats to names
    headers = _get_headers(rows[1])
    # Skip first 2 rows (headers)
    for row in rows[2:]:
        if 'pncPlayerRow' in row.attrs['class']:
            try:
                players.append(_from_content_row(row, headers))
            except InvalidPlayerRow:
                continue
        elif ('playerTableBgRowHead' in row.attrs['class'] or 'playerTableBgRowSubhead' in row.attrs['class']):
            # Ignore headers
            pass
        else:
            # Unknown row.
            print('Error')

    return players


def scrape_lineup(league_id, team_id, year):
    kwargs = {
        'league': league_id,
        'team': team_id,
        'year': year,
    }
    url = "http://games.espn.go.com/ffl/clubhouse?leagueId={league}&teamId={team}&seasonId={year}".format(**kwargs)
    content = requests.get(url).content
    soup = BeautifulSoup(content, "lxml")
    return _get_players(soup)

@segfaultmagnet
Copy link
Contributor

segfaultmagnet commented Aug 25, 2017

Found it: "playerInfo" retrieves all athletes ("players") currently on a fantasy team roster.

Credit: https://github.com/nickrobinson/fflpy/blob/master/fflpy.py

edit: "scoringPeriodId" can be passed as a parameter to fetch a specific week. Omitting it returns the latest week.

@fgblomqvist
Copy link
Author

fgblomqvist commented Aug 25, 2017

Did some reverse engineering earlier today and found a rosterInfo endpoint that takes leagueId and teamIds as parameters (can't remember whether teamIds is comma-separated or not, but shouldn't be hard to figure out). This is what's needed to get all the players on the specified team(s) in the specified league.

@segfaultmagnet
Copy link
Contributor

segfaultmagnet commented Aug 25, 2017

They are structured a little differently, but otherwise appear to be identical in content. The only real difference I'm seeing is that playerInfo pulls down every team's roster, while rosterInfo only returns one team's roster (mine). Specifying one or more teamIds didn't change anything for me. However, both of those behaviors may be because I'm sending cookies to access a private league. Are you able to get more than one roster in the same request?

@fgblomqvist
Copy link
Author

fgblomqvist commented Aug 25, 2017

Yes, I just tried and by comma-separating multiple team/entry IDs, I can get multiple (whichever I specify).
If I have time this weekend I could contribute at least a little bit to this project. More specifically the sign-in part of it. Just figured it out yesterday.

@drewski3420
Copy link

Just created a pull request that implements rosters. You can call get_roster(week) and will return player info along with projected and actual scores for the week.

`league = espnff.League(league_id, year, espn_s2, swid)

roster = league.teams[0].get_roster(week=1)

for player in roster:

print(player['player_id'])

print(player['name'])

print(player['position'])

print(player['actual_score'])

print(player['projected_score'])`

@CMorton737
Copy link

boxscore gives lineup information that can be served up by week and team_id. However it's only available for 2016, 2017

try:
http://games.espn.com/ffl/api/v2/boxscore?leagueId=1773242&seasonId=2016&teamId=1&scoringPeriodId=1

@drewski3420
Copy link

My pull request uses rosterInfo which seems more straightforward to me.

I haven't gone through the exercise of mapping the individual score breakdowns (yards, TDs, etc) however.

@CMorton737
Copy link

Sure, I agree. I just wanted to add because it seemed relevant. You've probably noticed that after two years ESPN purges Full Boxscore/Bench/Scoring Breakdown information. It appears -- at first glance -- that "boxscore" is the API handle for the Scoring Breakdown/Full Boxscore, and "rosterInfo" just serves up the most basic lineup.

@CMorton737
Copy link

CMorton737 commented Sep 16, 2017

Actually, looking into it more I see that's not the case. But it has the same issue where it is not accessible for seasons two years old.

What I would like to find out is API handle that serves up the minimized lineup information used to populate "QUICK BOX SCORE" from a season more than 2 years old (Im a big fan of league history)

@CMorton737
Copy link

If you're interested in the mapping of score breakdowns, I've done that in my fork. Feel free to use it.
https://github.com/CMorton737/espyn/blob/master/statmap.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants