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

如何使用Beautiful Soup抓取维基百科中带分组行的复杂JLPT表格并关联年份信息

如何使用Beautiful Soup抓取维基百科中带分组行的复杂JLPT表格并关联年份信息

我太懂你现在的困扰了——维基百科上这个JLPT的「Applications and results」表格设计得确实反直觉,年份只在每组的第一行露面,后面同一年的行完全不带年份标识,直接抓下来根本没法把数据和年份对应上。不过不用愁,咱们用Beautiful Soup就能在抓取阶段就把年份给每一行补上,不用事后手动去分组折腾!

下面是具体的步骤,全程尽量在Beautiful Soup里处理,Pandas只用来最后整理成表格:

1. 先获取并解析目标页面

首先咱们先把维基百科的JLPT页面抓下来,用Beautiful Soup解析找到目标表格:

import requests
from bs4 import BeautifulSoup

# JLPT维基百科页面URL
url = "https://en.wikipedia.org/wiki/Japanese-Language_Proficiency_Test"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

# 定位目标表格——这里用表格的class属性定位,维基百科的表格一般带wikitable类
target_table = soup.find('table', class_='wikitable')

2. 遍历行并动态关联年份

核心思路就是跟踪当前年份:遇到带年份的行就更新当前年份,后面的所有行都用这个年份,直到遇到下一个年份行。

咱们先处理表头,然后遍历每一行:

import re
import pandas as pd

current_year = None
rows_data = []

# 提取表头(清理掉[edit]这种多余文本)
header_cells = target_table.find('tr').find_all('th')
headers = [cell.get_text(strip=True).replace('[edit]', '') for cell in header_cells]

# 遍历所有数据行(跳过表头行)
for row in target_table.find_all('tr')[1:]:
    # 获取当前行的所有单元格(可能是<th>或<td>)
    cells = row.find_all(['th', 'td'])
    # 清理每个单元格的文本:去掉引用标记(比如[12])和多余空格
    cell_texts = [text.get_text(strip=True).split('[')[0] for text in cells]
    
    # 判断当前行是不是年份行:用正则匹配纯4位数字(清理引用后)
    year_match = re.match(r'^\d{4}$', cell_texts[0])
    if year_match:
        # 更新当前年份
        current_year = year_match.group()
        # 把年份行的数据加入列表(注意原行第一个单元格就是年份,直接保留)
        rows_data.append(cell_texts)
    else:
        # 非年份行,把当前年份补到第一个位置,再加上其他单元格内容
        # 原行第一个单元格是空的,所以替换成current_year
        rows_data.append([current_year] + cell_texts[1:])

3. 转换成DataFrame查看结果

现在所有行都已经带上对应的年份了,直接转成Pandas DataFrame就行:

df = pd.DataFrame(rows_data, columns=headers)

# 可选:调整数据类型,比如把Year列转成整数
df['Year'] = df['Year'].astype(int)

# 看看结果
print(df.head())

这样得到的DataFrame就是你想要的格式——每一行都有对应的年份,完全不用事后手动分组。而且大部分逻辑都在Beautiful Soup阶段完成,Pandas只是做最后的格式化,符合你“少做后处理”的需求。

小提示

如果遇到年份格式不是纯4位数字的情况(比如偶尔出现年份范围),可以稍微调整正则表达式,比如改成re.match(r'^\d{4}(-\d{4})?$', cell_texts[0]),这样就能兼容年份范围的情况了。

备注:内容来源于stack exchange,提问作者Non Sum Japonicus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 14:03:13