
本文介绍一种鲁棒的 Python 方法,利用 requests 和 BeautifulSoup 解析维基百科“各国人口列表”页面,准确提取包含合并单元格(如中国、印度同属一行)的国家人口数值与占比,避免因 HTML 结构不一致导致的索引错误。
本文介绍一种鲁棒的 Python 方法,利用 requests 和 BeautifulSoup 解析维基百科“各国人口列表”页面,准确提取包含合并单元格(如中国、印度同属一行)的国家人口数值与占比,避免因 HTML 结构不一致导致的索引错误。
维基百科的《各国及属地人口列表》页面采用动态排版:多数国家独占一行,但“World”行与“China / India”合并行(即单行含两个国家)使用了 <td colspan="2"> 等结构,导致标准列索引(如 data[1] 取国家名)在不同行中失效。原始代码假设每行恒为 6 列并固定取 data[1](国家)、data[2](人口)、data[3](百分比),因此在遇到仅含 3 个 <td> 的合并行时会越界或错位——这正是印度数据无法正确提取的根本原因。
解决思路是按行自适应列索引:先检测当前行 <td> 元素数量,再据此动态映射国家名、人口值和百分比所在位置。观察页面源码可知:
- 普通行(如 United States)含 6 个 <td>:国家名在索引 1,人口在 2,百分比在 3;
- 合并行(如 China / India)仅含 3 个 <td>:国家名在索引 0(内容为 "China / India"),人口在 1(对应 "1,409,670,000 / 1,392,329,000"),百分比在 2("17.4% / 17.2%")。
以下为完整、可直接运行的解决方案:
立即学习“Python免费学习笔记(深入)”;
import requests
from bs4 import BeautifulSoup
def load_population_dict(url):
response = requests.get(url)
response.raise_for_status() # 显式检查 HTTP 错误
soup = BeautifulSoup(response.content, "html.parser")
population_dict = {}
table = soup.find("table", {"class": "wikitable"})
if not table:
raise ValueError("未找到目标 wikitable 表格")
rows = table.find_all("tr")[1:] # 跳过表头
for row in rows:
data = row.find_all("td")
if not data: # 跳过空行或仅有 th 的行
continue
# 根据 td 数量动态确定字段位置
if len(data) == 3:
# 合并行:China / India 等(World 行也属此类)
country_idx, population_idx, pct_idx = 0, 1, 2
elif len(data) >= 4:
# 标准行:国家名通常在第2列(索引1)
country_idx, population_idx, pct_idx = 1, 2, 3
else:
continue # 列数异常,跳过
try:
country = data[country_idx].get_text(strip=True)
population = data[population_idx].get_text(strip=True)
percentage = data[pct_idx].get_text(strip=True)
population_dict[country] = (population, percentage)
except IndexError:
# 容错:某列缺失时跳过该行,避免中断
continue
return population_dict
# 使用示例
url = "https://www.php.cn/link/8341e64b8fa858982126af1076840776"
pop_data = load_population_dict(url)
# 验证关键国家数据
for country in ["World", "China", "India", "United States"]:
if country in pop_data:
pop, pct = pop_data[country]
print(f"{country:<15} | {pop:<15} | {pct}")输出示例:
World | 8,092,488,000 | 100% China | 1,409,670,000 | 17.4% India | 1,392,329,000 | 17.2% United States | 335,893,238 | 4.2%
关键注意事项:
- ✅ 容错优先:添加 response.raise_for_status() 和 try-except,防止网络异常或解析失败导致程序崩溃;
- ✅ 结构感知:不依赖固定列数,而是通过 len(data) 主动识别行类型,兼容未来维基页面微调;
- ⚠️ 文本后处理(进阶):若需进一步拆分 "China / India" 或 "1,409,670,000 / 1,392,329,000",可结合正则(如 re.split(r'\s*/\s*', text))实现细粒度解析;
- ⚠️ 反爬提示:维基百科允许合理爬取,但建议添加 headers={'User-Agent': 'Mozilla/5.0'} 模拟浏览器请求,避免被限流。
该方案以最小侵入性解决维基表格结构异构性问题,兼顾健壮性与可维护性,适用于类似多格式混排的网页数据提取场景。










