
本文介绍如何使用 BeautifulSoup 解析网页中的 表格结构,并通过逐行提取关键字段(如姓名、位置、球队、年龄、出生年份),最终构建结构清晰、可直接分析的 Pandas DataFrame。
本文介绍如何使用 beautifulsoup 解析网页中的 `
` 表格结构,并通过逐行提取关键字段(如姓名、位置、球队、年龄、出生年份),最终构建结构清晰、可直接分析的 Pandas DataFrame。在网页数据采集(Web Scraping)中,将 HTML 表格内容转化为结构化 DataFrame 是常见且关键的一步。以 FBRef 网站为例,其球员统计页面采用语义化
以下为完整、健壮的实现流程:
import requests
from bs4 import BeautifulSoup
import pandas as pd
# 1. 获取网页内容
url = "https://fbref.com/en/comps/9/stats/Premier-League-Stats"
res = requests.get(url)
res.raise_for_status() # 确保请求成功
# 2. 解析 HTML(无需正则清理注释,lxml 自动处理更稳定)
soup = BeautifulSoup(res.text, 'lxml')
# 3. 定位目标表格主体 —— 第三个 <tbody>(对应球员基础统计)
player_tbody = soup.find_all("tbody")[2]
# 4. 初始化数据列表
data = []
columns = ['Name', 'Position', 'Team', 'Age', 'Birth Year']
# 5. 遍历每行 <tr>,安全提取字段(添加异常处理)
for row in player_tbody.find_all("tr"):
try:
# 提取姓名:优先取 <a> 标签文本,避免误抓 th 中的排序符号
name_tag = row.find("a")
name = name_tag.get_text(strip=True) if name_tag else ""
# 按 data-stat 属性精准定位各列
position = row.find("td", {"data-stat": "position"}).get_text(strip=True) if row.find("td", {"data-stat": "position"}) else ""
team = row.find("td", {"data-stat": "team"}).get_text(strip=True) if row.find("td", {"data-stat": "team"}) else ""
age = row.find("td", {"data-stat": "age"}).get_text(strip=True) if row.find("td", {"data-stat": "age"}) else ""
birth_year = row.find("td", {"data-stat": "birth_year"}).get_text(strip=True) if row.find("td", {"data-stat": "birth_year"}) else ""
data.append([name, position, team, age, birth_year])
except AttributeError:
# 跳过无完整字段的行(如分组标题、空行)
continue
# 6. 构建 DataFrame
df = pd.DataFrame(data, columns=columns)
# 可选:清洗 Age 字段(如 "24-084" → "24")
df['Age'] = df['Age'].str.extract(r'^(\d+)', expand=False)
print(df.head())<p>✅ <strong>关键注意事项</strong>: </p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d3191a227.jpg" alt="DeepBI DHTML 页面生成器" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="overflowclass">DeepBI DHTML 页面生成器</a>
<p class="overflowclass">生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:
- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;
- 提及位于 `apps/console/src/featur</p>
</div>
<a rel="nofollow" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul><li>
<strong>避免硬编码索引</strong>:soup.find_all("tbody")[2] 依赖页面结构稳定性;生产环境建议结合 CSS 选择器(如 soup.select("table.stats_table tbody")[0])或查找含特定 class 的 <tbody>。 <li>
<strong>容错处理必不可少</strong>:使用 .find() 后务必检查返回值是否为 None,否则会触发 AttributeError;try...except 可保障批量解析不中断。 </li>
<li>
<strong>文本清洗不可省略</strong>:.get_text(strip=True) 自动去除前后空白与换行;对 Age 等复合格式字段,建议用正则进一步标准化。 </li>
<li>
<strong>反爬提示</strong>:FBRef 对高频请求可能返回 403;建议添加 headers={'User-Agent': 'Mozilla/5.0...'} 并控制请求频率。</li>
<p>最终生成的 DataFrame 具备标准列名与齐整数据,可直接用于后续分析(如按 Position 分组统计、筛选 Birth Year > 2000 的年轻球员等),真正实现从 HTML 到可计算数据的无缝转化。</p>
</tbody>
</li></ul></a>
</tr>
</tbody>
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










