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

遍历HTML tbody生成DataFrame遇数据重复问题求助(NHL球队数据)

爬取NHL 2022-2023赛季球队数据时的数据重复问题排查

问题概述

爬取NHL 2022-2023赛季球队数据时,通过requests获取目标网页内容,使用BeautifulSoup解析HTML表格。表头提取逻辑正常,但遍历<tbody>生成数据行时出现数据重复,无法得到32条对应球队的有效数据。

目标网页结构(简化版)

<table>
    <colgroup>
        <col />
    </colgroup>
    <thead>
        <tr>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td></td>
        </tr>
    </tbody>
</table>

现有Python代码

import requests
from bs4 import BeautifulSoup
import pandas as pd

##### LOAD IN NHL TEAM STATS ######

# Send a GET request to the Natural Stat Trick website and retrieve the HTML content
nhl_team_stats = "https://www.naturalstattrick.com/teamtable.php?fromseason=20222023&thruseason=20222023&stype=2&sit=all&score=all&rate=y&team=all&loc=B&gpf=410&fd=&td="
nhl_team_stats_response = requests.get(nhl_team_stats)
nhl_team_stats_html_content = nhl_team_stats_response.content

# Use BeautifulSoup to parse the HTML content
nhl_team_stats_soup = BeautifulSoup(nhl_team_stats_html_content, "html.parser")

# Find the table containing the NHL schedule data
nhl_team_stats_table = nhl_team_stats_soup.find("table", attrs={"id": "teams"})

# Extract the table headers
nhl_team_stats_headers = []
for thead in nhl_team_stats_table.find_all('thead'):
    for tr in thead.find_all("tr"):
        for th in tr.find_all("th"):
            nhl_team_stats_headers.append(th.text.strip())

nhl_team_stats_headers[0] = "ID"

print(nhl_team_stats_headers)

# Extract the table rows
nhl_team_stats_rows = []
teams_list = []
tbody = nhl_team_stats_table.find("tbody")
for tr in tbody.find_all("tr"):
    row = []
    for td in tr.find_all(["td"]):
        cell_text = td.text.strip()
        row.append(cell_text)
    nhl_team_stats_rows.append(row)
    teams_list.append(row[1])

print(nhl_team_stats_rows)

# print(teams_list)

# Convert the nhl_team_stats_rows to a DataFrame
# nhl_team_stats_df = pd.DataFrame(nhl_team_stats_rows, nhl_team_stats_headers)

# Get the mean xGF/60
# mean_gf = pd.to_numeric(nhl_team_stats_df[22], errors='coerce').mean()

# Convert the teams_list to a DataFrame
# teams_df = pd.DataFrame(teams_list, columns=["Team"])

问题原因与解决方法

核心问题

目标网页的<tbody>中存在无效行(比如隐藏的响应式折叠行、汇总统计行),这些行被find_all("tr")一并抓取,导致数据重复或冗余。

解决方案

通过以下两种方式过滤无效行:

  1. 按单元格数量匹配过滤
    只有当行的单元格数量与表头字段数量一致时,才视为有效球队数据行:

    # 修改后的行提取逻辑
    nhl_team_stats_rows = []
    teams_list = []
    tbody = nhl_team_stats_table.find("tbody")
    header_count = len(nhl_team_stats_headers)
    
    for tr in tbody.find_all("tr"):
        tds = tr.find_all("td")
        # 只保留单元格数量与表头一致的行
        if len(tds) == header_count:
            row = [td.text.strip() for td in tds]
            nhl_team_stats_rows.append(row)
            teams_list.append(row[1])
    
  2. 按行的class属性过滤
    查看网页实际HTML,无效行通常带有特定class(比如hidden),直接过滤这类行:

    # 修改后的行提取逻辑
    nhl_team_stats_rows = []
    teams_list = []
    tbody = nhl_team_stats_table.find("tbody")
    
    for tr in tbody.find_all("tr", class_=lambda x: x != "hidden"):  # 替换为实际无效行的class
        row = [td.text.strip() for td in tr.find_all("td")]
        nhl_team_stats_rows.append(row)
        teams_list.append(row[1])
    

验证结果

修改后重新运行代码,teams_list应包含32条唯一的球队名称,nhl_team_stats_rows也将对应32条有效数据行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:42:31