如何使用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
相关产品推荐
相关产品推荐

