You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用BeautifulSoup遍历HTML采集NBA全维度排名数据

实现方案

原代码存在几个明显问题:

  • 重复发起两次相同HTTP请求,属于冗余代码
  • 遍历tbody的循环与后续行遍历循环平级,rows变量会被最后一个tbody覆盖,存在数据遗漏风险
  • 仅硬编码定位东部联盟单张表,未覆盖西部联盟、6个分赛区、全联盟三个维度的所有排名表
  • 仅提取球队名单个字段,未采集胜场、负场、胜率等其他排名指标
  • 裸except会吞掉所有运行错误,排查问题困难
  • 额外注意:该站点的分赛区排名表默认写在HTML注释中,直接调用find方法无法定位,必须单独处理注释内容。

整体实现逻辑:

  • 单次请求拉取页面源码
  • 同时抓取页面直接可见的联盟排名、全联盟排名表,以及注释中隐藏的分赛区排名表,覆盖所有需要的数据源
  • 遍历每张表时先记录表所属的维度名称(如东部联盟、大西洋赛区、全联盟排名等)
  • 逐行解析时跳过表头分隔行,按字段属性提取所有数据,统一结构化存储
  • 移除无意义的全局异常捕获,通过条件判断跳过无效行,避免错误被吞

完整可运行代码:

import requests
from bs4 import BeautifulSoup, Comment

url = 'https://www.basketball-reference.com/leagues/NBA_2022_standings.html'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'html.parser')

standings_tables = []
# 收集直接可见的东西部联盟、全联盟排名表
for table in soup.find_all('table'):
    table_id = table.get('id', '')
    if table_id.startswith('confs_standings') or table_id == 'expanded_standings':
        standings_tables.append((table_id, table))

# 收集注释中隐藏的分赛区排名表
for comment in soup.find_all(string=lambda x: isinstance(x, Comment)):
    comment_soup = BeautifulSoup(comment, 'html.parser')
    for table in comment_soup.find_all('table'):
        if table.get('id', '').startswith('divs_standings'):
            standings_tables.append((table.get('id'), table))

all_standings = []
for table_id, table in standings_tables:
    # 获取当前表的维度名称
    dimension = table.find('caption').text.strip()
    # 遍历表体行
    for row in table.find('tbody').find_all('tr'):
        # 跳过分隔用的标题行(这类行没有球队跳转链接)
        team_cell = row.find('th')
        if not team_cell or not team_cell.find('a'):
            continue
        # 组装单条数据
        item = {'dimension': dimension}
        item['rank'] = team_cell.text.strip().split()[0] # 提取排名数字
        item['team'] = team_cell.find('a').text.strip()
        # 提取其余所有数据列
        for td in row.find_all('td'):
            stat_key = td.get('data-stat')
            item[stat_key] = td.text.strip()
        all_standings.append(item)

# 测试输出
for row in all_standings[:10]:
    print(row)

# 后续连接数据库后,直接遍历all_standings列表批量插入即可

代码说明:

  • 表定位通过id前缀规则匹配,不需要手动硬编码每个表的id,后续爬取其他赛季只需要修改URL中的年份参数即可复用
  • 自动处理注释内的隐藏表格,不会遗漏分赛区维度的数据
  • 最终采集结果存在all_standings列表中,每个元素是结构化字典,包含所属维度、排名、球队名、胜场、负场、胜率、胜场差、主客场战绩、同赛区/同联盟战绩等全部页面展示字段,可直接对接数据库插入逻辑
  • 字段key取自HTML标签自带的data-stat属性,不依赖列的固定顺序,即使网站微调列顺序也不会出现数据错位问题
  • 移除了裸异常捕获,通过判断球队链接是否存在来跳过无效行,运行出错时会直接抛出具体错误信息,方便调试

内容的提问来源于stack exchange,提问作者DrewS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:24:20