从维基百科爬取表格遇ValueError:标量值需传入索引
问题解决:处理法国陆军装备表格时的ValueError错误
错误原因
你遇到的ValueError: If using all scalar values, you must pass an index,本质是从法国陆军装备页面匹配到的表格中,你试图提取的某一列不存在,或者该列返回的是单个标量值而非Series。
查看法国陆军装备页面的AMX Leclerc对应表格会发现,它的列名和意、英两国的表格不一致:你代码里依赖的Number列,在法国的表格里实际叫In service。当尝试提取data[0]["Number"]时,因为列不存在,pandas返回了标量NaN,后续用这些标量创建DataFrame时就会触发该错误。
修复方案
方案1:针对不同表格适配列名映射
修改函数,允许传入列名映射参数,兼容不同页面的表格结构:
import pandas as pd import numpy as np def createTable(url, match, col_mapping=None): # 默认列名映射,适配意、英表格 default_mapping = { "Name": "Name", "Origin": "Origin", "Type": "Type", "Number": "Number" } # 合并自定义映射 if col_mapping: default_mapping.update(col_mapping) data = pd.read_html(url, match=match) df = data[0].rename(columns=lambda x: x.strip()) # 去除列名前后空格 # 提取需要的列,用映射后的名称 selected_cols = {new_col: df[old_col] for new_col, old_col in default_mapping.items()} df_clean = pd.DataFrame(selected_cols) df_clean.replace("?", np.nan, inplace=True) df_clean['Number'] = df_clean['Number'].replace(to_replace={r"\(.*\)": "", r"\[.*\]": ""}, regex=True) return df_clean
调用时给法国表格传入对应的列名映射:
df_avIT = createTable( "https://en.wikipedia.org/wiki/List_of_equipment_of_the_Italian_Army", "125 To be upgraded and remain in service until 2035" ) df_avUK = createTable( "https://en.wikipedia.org/wiki/List_of_equipment_of_the_British_Army", "Challenger 2" ) df_avFR = createTable( "https://en.wikipedia.org/wiki/List_of_equipment_of_the_French_Army", "AMX Leclerc", col_mapping={"Number": "In service"} # 法国表格的数量列名为"In service" )
方案2:增强函数健壮性,自动匹配备选列名
如果需要函数自动适配不同表格,可以添加列存在性检查,自动查找备选列名:
import pandas as pd import numpy as np def createTable(url, match): data = pd.read_html(url, match=match) df = data[0].rename(columns=lambda x: x.strip()) # 定义需要的列及备选名称 required_cols = { "Name": ["Name"], "Origin": ["Origin", "Country of origin"], "Type": ["Type"], "Number": ["Number", "In service", "Quantity"] } selected_data = {} for new_col, possible_names in required_cols.items(): for col_name in possible_names: if col_name in df.columns: selected_data[new_col] = df[col_name] break else: # 未找到匹配列时填充NaN selected_data[new_col] = pd.Series([np.nan]*len(df)) df_clean = pd.DataFrame(selected_data) df_clean.replace("?", np.nan, inplace=True) df_clean['Number'] = df_clean['Number'].replace(to_replace={r"\(.*\)": "", r"\[.*\]": ""}, regex=True) return df_clean
调用时无需额外参数,函数会自动适配:
df_avIT = createTable( "https://en.wikipedia.org/wiki/List_of_equipment_of_the_Italian_Army", "125 To be upgraded and remain in service until 2035" ) df_avUK = createTable( "https://en.wikipedia.org/wiki/List_of_equipment_of_the_British_Army", "Challenger 2" ) df_avFR = createTable( "https://en.wikipedia.org/wiki/List_of_equipment_of_the_French_Army", "AMX Leclerc" )
验证方法
可以先单独打印法国表格的列名,确认差异:
data_fr = pd.read_html("https://en.wikipedia.org/wiki/List_of_equipment_of_the_French_Army", match="AMX Leclerc") print(data_fr[0].columns)
输出会显示该表格的列名,比如['Name', 'Origin', 'Type', 'In service', ...],从而确认Number列不存在,需要替换为In service。
内容的提问来源于stack exchange,提问作者ale maglia
相关产品推荐
相关产品推荐

