
本文介绍如何将多赛季横向堆叠的 scraped 英超积分榜数据(每赛季占一行、列数极多)重构为规范的纵向结构化 dataframe,包含位置、俱乐部、比赛统计与近期战绩等 11 个标准字段。
本文介绍如何将多赛季横向堆叠的 scraped 英超积分榜数据(每赛季占一行、列数极多)重构为规范的纵向结构化 dataframe,包含位置、俱乐部、比赛统计与近期战绩等 11 个标准字段。
在网页爬虫实践中,尤其是使用 Selenium 抓取多赛季积分榜时,常因 HTML 结构限制导致数据以「横向展开」方式被扁平化存储——例如每个赛季的 20 支球队信息被拼接为单行,形成类似 3 行 × 160 列 的宽表。这种结构既不符合分析习惯,也难以直接用于可视化或建模。解决的关键在于:将原始嵌套列表按逻辑单元切分、解包并重组为长格式(long format)DataFrame。
以下是以 pandas 为主、辅以标准库的高效重构方案:
✅ 核心思路
- 扁平化 + 分块:将三层嵌套列表 table_data(3 个赛季 × 每赛季 20 队 × 每队 8 字段)展平为一维序列,再按每队 8 个字段切分为独立记录;
- 字段解析:对第 3 列(如 '33 23 5 5 77 26 51 74')进行空格分割,提取 Played, Won, Draw, Lost, GF, GA, GD, Points 八项数值;
- 合并结构化字段:将位置(Position)、队名(Club)、解析后的统计字段、以及后续 5 场战绩(Form)拼接为统一 DataFrame;
- 重命名列:赋予语义清晰的列名,便于后续分析。
? 完整代码实现
import pandas as pd
from itertools import chain, batched # Python ≥3.12;若版本较低,请用 list comprehension 或 more-itertools
# 假设 table_data 已加载(即问题中提供的三季数据)
df = (
pd.DataFrame(batched(chain.from_iterable(table_data), 8))
.pipe(
lambda raw: pd.concat([
raw.iloc[:, :2], # Position, Club
raw[2].str.split(expand=True).astype(int), # 解析 "33 23 5 5 77 26 51 74" → 8 列数值
raw.iloc[:, 3:].agg(" ".join, axis=1), # 合并后续 5 列为单字段 Form(如 "D W W L W")
], axis=1)
)
.set_axis([
"Position", "Club", "Played", "Won", "Draw", "Lost",
"GF", "GA", "GD", "Points", "Form"
], axis=1)
)
# ✅ 输出为 60 行 × 11 列的标准长表(3 季 × 20 队)
print(df.head())
print(f"\nShape: {df.shape}") # → (60, 11)
? 兼容性提示:若使用 Python
from itertools import islice def batched(iterable, n): iterator = iter(iterable) while batch := list(islice(iterator, n)): yield batch
⚠️ 注意事项与增强建议
-
赛季标识缺失:当前结果未区分赛季。如需保留时间维度,可在 .pipe() 前添加赛季编号列,例如:
season_ids = [f"2021/22"] * 20 + [f"2022/23"] * 20 + [f"2023/24"] * 20 df.insert(0, "Season", season_ids)
- 数据清洗强化:Club 列可能存在多余空格(如 "Tottenham Hotspur "),建议追加 .str.strip();
-
Form 字段扩展:若需进一步拆分为 Form_1, Form_2, ..., Form_5,可用:
form_df = df["Form"].str.split(" ", expand=True).add_prefix("Form_") df = pd.concat([df.drop("Form", axis=1), form_df], axis=1) -
异常处理:实际爬虫中可能因页面变动导致某赛季数据长度异常,建议加入断言校验:
total_teams = sum(len(season) // 8 for season in table_data) assert len(df) == total_teams, f"Expected {total_teams} rows, got {len(df)}"
通过上述方法,你将原始「宽而扁」的爬虫输出,精准转化为符合数据分析惯例的纵向结构化表格——每一行代表一支球队在一个赛季中的完整表现,列名语义明确、类型正确,可直接用于统计分析、时间序列对比或可视化绘图。











