python - 从下拉菜单 Python 中抓取每个表
问题描述
我希望从以下 NCAA 统计页面中获取 Division 3 大学篮球统计数据:
https://stats.ncaa.org/rankings/change_sport_year_div
要访问我所在的页面,请单击链接后,选择 Sport = Men's Basketball,Year = 2019-2020,Div = III
单击链接后,左上角表格上方有一个下拉菜单。它被标记为“附加统计信息”。对于每个统计数据,都有一个表格,您可以获取其中的 excel 文件,但我想提高效率。我在想可能有一种方法可以使用 BeautifulSoup(甚至可能是 pd.read_html)遍历下拉栏,以获取列出的每个统计信息的数据框。有没有办法做到这一点?手动浏览每个统计信息,下载 excel 文件,然后将 excel 文件读入 pandas 会很痛苦。谢谢你。
解决方案
这是我的建议,使用来自Scott Romerequests
的,beautifulsoup
和一个很棒的 html 表解析器的组合(我修改了一些函数来删除和去除空格)。parse_html_table
\n
首先,当您检查页面的源代码时,您可以看到它采用以下形式:"https://stats.ncaa.org/rankings/national_ranking?academic_year=2020.0&division=3.0&ranking_period=110.0&sport_code=MBB&stat_seq=145.0"
例如 stat 145 即“得分进攻”。
因此,您可以在每个 url 上使用以下代码,方法是将 替换为145.0
与不同统计信息对应的值,您可以在检查页面的源代码时看到这些值。
# <option value="625">3-pt Field Goal Attempts</option>
# <option value="474">Assist Turnover Ratio</option>
# <option value="216">Assists Per Game</option>
# ...
对于特定的统计数据,例如得分进攻,您可以使用以下代码将表格提取为 pandas DataFrame:
import pandas as pd
from bs4 import BeautifulSoup
import requests
el = "https://stats.ncaa.org/rankings/national_ranking?academic_year=2020.0&division=3.0&ranking_period=110.0&sport_code=MBB&stat_seq=145.0"
page = requests.get(el).content.decode('utf-8')
soup = BeautifulSoup(page, "html.parser")
ta = soup.find_all('table', {"id": "rankings_table"})
# Scott Rome function tweaked a bit
def parse_html_table(table):
n_columns = 0
n_rows = 0
column_names = []
# Find number of rows and columns
# we also find the column titles if we can
for row in table.find_all('tr'):
# Determine the number of rows in the table
td_tags = row.find_all('td')
if len(td_tags) > 0:
n_rows += 1
if n_columns == 0:
# Set the number of columns for our table
n_columns = len(td_tags)
# Handle column names if we find them
th_tags = row.find_all('th')
if len(th_tags) > 0 and len(column_names) == 0:
for th in th_tags:
column_names.append(th.get_text())
# Safeguard on Column Titles
if len(column_names) > 0 and len(column_names) != n_columns:
raise Exception("Column titles do not match the number of columns")
columns = column_names if len(column_names) > 0 else range(0, n_columns)
df = pd.DataFrame(columns=columns,
index=range(0, n_rows))
row_marker = 0
for row in table.find_all('tr'):
column_marker = 0
columns = row.find_all('td')
for column in columns:
df.iat[row_marker, column_marker] = column.get_text()
column_marker += 1
if len(columns) > 0:
row_marker += 1
# remove \n
for col in df:
try:
df[col] = df[col].str.replace("\n", "")
df[col] = df[col].str.strip()
except ValueError:
pass
# Convert to float if possible
for col in df:
try:
df[col] = df[col].astype(float)
except ValueError:
pass
return df
example = parse_html_table(ta[0])
结果是
Rank Team GM W-L PTS PPG
0 1 Greenville (SLIAC) 27.0 14-13 3,580 132.6
1 2 Grinnell (Midwest Conference) 25.0 13-12 2,717 108.7
2 3 Pacific (OR) (NWC) 25.0 7-18 2,384 95.4
3 4 Whitman (NWC) 28.0 20-8 2,646 94.5
4 5 Valley Forge (ACAA) 22.0 12-11 2,047 93.0
...
现在,您要做的就是将其应用于上述所有统计值。
您可以为上面的代码创建一个函数,并在 for 循环中将其应用于所有可能值列表中"https://stats.ncaa.org/rankings/national_ranking?academic_year=2020.0&division=3.0&ranking_period=110.0&sport_code=MBB&stat_seq={}".format(stat)
的url。stat
希望能帮助到你。
推荐阅读
- matlab - 微分方程斜率场和柯西解
- c# - 创建新的 T、X 并使用反射 C# 填充类
- maven - 尽管添加了 log4j2.xml 文件,但无法使用“Selenium”和“Cucumber”依赖项“清理安装 -DskipTests”我的项目
- azure - 将自定义域设为“主要”的好处
- mysql - 查询多对多关系以查看是否存在一个值但不存在另一个值?
- javascript - 如何使用带有括号的动态 id 的 onchange 函数
- r - R Shiny:将变量分组在一个唯一的标签下,并在反应输出中使用该标签
- python - 如何使用 Folium 在成对的开始和结束地理空间点之间绘制路线?
- python - 如何将字符串传递给shell脚本
- shell - 如何逐字比较2个文件并将不同的单词存储在结果输出文件中