Python 用于比较足球运动员的大学母校与 NFL Fantasy Football 总产量的网络抓取方法

Python Webscraping Approach for Comparing Football Players' college alma maters with total NFL Fantasy Football output

我正在寻找一个数据科学项目,在该项目中我将能够按球员就读的大学汇总梦幻足球得分(例如,阿拉巴马州在 NFL 中有 56 名现役球员,所以我将通过一个数据库并将他们所有的幻想点加起来与其他学校进行比较。

我在看网站: https://fantasydata.com/nfl/fantasy-football-leaders?season=2020&seasontype=1&scope=1&subscope=1&aggregatescope=1&range=3

我打算使用 Beautiful Soup 来收集球员和统计数据的行,并最终收集梦幻足球积分。

但是,我无法弄清楚如何提取玩家的大学母校。为此,我必须:

这里有什么建议吗?

不需要 Selenium 或其他无头的自动化浏览器。太过分了。

如果您查看浏览器的网络流量,您会注意到您的浏览器向此 REST API 端点发出 POST 请求:https://fantasydata.com/NFL_FantasyStats/FantasyStats_Read

如果 POST 请求格式正确,API 响应 JSON,其中包含每个玩家的信息。通常,此信息将用于使用 JavaScript 异步填充 DOM。那里有很多信息,但不幸的是,大学信息不是 JSON 响应的一部分。但是,有一个字段 PlayerUrlString,它是给定玩家个人资料页面的相对 URL,它确实包含大学名称。所以:

  • 向 API 发出 POST 请求以获取有关所有玩家的信息

对于响应中的每个玩家 JSON:

  • 访问该玩家的个人资料
  • 使用BeautifulSoup从当前文件中提取学院名称 玩家资料

代码:

def main():

    import requests
    from bs4 import BeautifulSoup

    url = "https://fantasydata.com/NFL_FantasyStats/FantasyStats_Read"

    data = {
        "sort": "FantasyPoints-desc",
        "pageSize": "50",
        "filters.season": "2020",
        "filters.seasontype": "1",
        "filters.scope": "1",
        "filters.subscope": "1",
        "filters.aggregatescope": "1",
        "filters.range": "3",
    }

    response = requests.post(url, data=data)
    response.raise_for_status()

    players = response.json()["Data"]
    for player in players:
        url = "https://fantasydata.com" + player["PlayerUrlString"]

        response = requests.get(url)
        response.raise_for_status()

        soup = BeautifulSoup(response.content, "html.parser")

        college = soup.find("dl", {"class": "dl-horizontal"}).findAll("dd")[-1].text.strip()

        print(player["Name"] + " went to " + college)

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

输出:

Patrick Mahomes went to Texas Tech
Kyler Murray went to Oklahoma
Aaron Rodgers went to California
Russell Wilson went to Wisconsin
Josh Allen went to Wyoming
Deshaun Watson went to Clemson
Ryan Tannehill went to Texas A&M
Lamar Jackson went to Louisville
Dalvin Cook went to Florida State
...

您还可以在 data 词典中编辑 pageSize POST 参数。 50 对应于 JSON 响应中前 50 名玩家的信息(根据其他 POST 参数设置的过滤器)。更改此值将在 JSON 响应中产生更多或更少的玩家。

我同意,如果他们在那里,API 是必经之路。我的第二个“转到”是 pandas' .read_html()(它在后台使用 BeautifulSoup 来解析 <table> 标签。这是使用 ESPN api 的替代解决方案获取团队名单 links,然后使用 pandas 从每个 link 中提取 table。省去了必须遍历每个球员以获得大学的麻烦(我希望他们只是有一个 api 返回所有玩家。nfl.com 曾经有过,但不再公开,据我所知)。

代码:

import requests
import pandas as pd
    
url = 'https://site.web.api.espn.com/apis/common/v3/sports/football/nfl/athletes/101'

all_teams = []
roster_links = []
for i in range(1,35):
    url = 'http://site.api.espn.com/apis/site/v2/sports/football/nfl/teams/{teamId}'.format(teamId=i)
    jsonData = requests.get(url).json()
    print (jsonData['team']['displayName'])
    for link in jsonData['team']['links']:
        if link['text'] == 'Roster':
            roster_links.append(link['href'])
            break
    
for link in roster_links:
    print (link)
    tables = pd.read_html(link)
    df = pd.concat(tables).drop('Unnamed: 0',axis=1)
    df['Jersey'] = df['Name'].str.replace("([A-Za-z.' ]+)", '')
    df['Name'] = df['Name'].str.extract("([A-Za-z.' ]+)")
    all_teams.append(df)

final_df = pd.concat(all_teams).reset_index(drop=True)

输出:

print (final_df)
                  Name POS  Age      HT       WT Exp           College Jersey
0            Matt Ryan  QB   35   6' 4"  217 lbs  13    Boston College      2
1          Matt Schaub  QB   39   6' 6"  245 lbs  17          Virginia      8
2       Todd Gurley II  RB   26   6' 1"  224 lbs   6           Georgia     21
3           Brian Hill  RB   25   6' 1"  219 lbs   4           Wyoming     23
4       Qadree Ollison  RB   24   6' 1"  232 lbs   2        Pittsburgh     30
               ...  ..  ...     ...      ...  ..               ...    ...
1772    Jonathan Owens   S   25  5' 11"  210 lbs   2  Missouri Western     36
1773       Justin Reid   S   23   6' 1"  203 lbs   3          Stanford     20
1774  Ka'imi Fairbairn  PK   26   6' 0"  183 lbs   5              UCLA      7
1775       Bryan Anger   P   32   6' 3"  205 lbs   9        California      9
1776         Jon Weeks  LS   34  5' 10"  242 lbs  11            Baylor     46

[1777 rows x 8 columns]