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

使用find_all('tr')爬取时为何会获取到表格表头?

维基百科标普500页面爬取:包含表头行的问题及解决

问题描述

作为网页爬取新手,我从维基百科标普500页面提取数据,使用.find_all('tr')查找表格条目,但第一个匹配结果却是表格表头。我原本以为表头需要通过查找<th>标签获取。我的临时解决方法是将第一个条目加入跳过列表,并添加if语句进行过滤,代码如下:

url = 'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies'
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, 'lxml')
table = soup.find('tbody')
trs = table.find_all('tr')
symbol_names = []
skip = ['Symbol']
for tr in trs:
    symbol = tr.a.text
    if symbol not in skip:
        symbol_names.append(symbol)

想请教为何会出现这种情况?我哪里操作有误?

原因分析

这是因为维基百科的表格结构里,表头行本身就是一个<tr>元素,它的内部单元格用<th>标签定义,但整个表头行依然属于<tbody>下的子元素。你用table.find_all('tr')会把所有<tbody>内的<tr>都提取出来,自然包括表头那一行。

另外你之前的误区是:表头不是只能通过<th>获取,<th>只是表头的单元格标签,整个表头行还是由<tr>包裹的,所以它会出现在<tr>的搜索结果里。而且这个表头行的<th>里恰好也有<a>标签("Symbol"是带链接的),所以你能通过tr.a.text拿到表头文本,才需要额外过滤。

更合理的解决方法

没必要用跳过列表这种依赖文本内容的方式,直接从结构上区分表头行和数据行更可靠:

  1. 直接跳过第一行
    因为表头固定是<tbody>下的第一个<tr>,可以直接切片去掉:

    trs = table.find_all('tr')[1:]  # 从索引1开始取,跳过第一个表头行
    symbol_names = []
    for tr in trs:
        symbol = tr.a.text
        symbol_names.append(symbol)
    
  2. 通过标签判断表头行
    检查当前<tr>是否包含<th>标签,包含的话就是表头行,直接跳过:

    trs = table.find_all('tr')
    symbol_names = []
    for tr in trs:
        if tr.find('th'):
            continue
        symbol = tr.a.text
        symbol_names.append(symbol)
    
  3. 直接定位数据行
    数据行的单元格用<td>标签,所以可以直接找包含<td>的<tr>:

    symbol_names = []
    # 直接找带有<td>的<tr>,也就是数据行
    data_rows = table.find_all('tr', lambda tag: tag.find('td') is not None)
    for tr in data_rows:
        symbol = tr.a.text
        symbol_names.append(symbol)
    

内容的提问来源于stack exchange,提问作者M33G0

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 21:43:15