使用Pandas read_html爬取SEC DEF 14A表格并识别合并多行表头
SEC DEF 14A表格表头合并解决方案
核心思路
DEF 14A中的薪酬表格表头行统一特征为:仅包含描述性文本、几乎没有有效业务数值(薪资、奖金等金额),可以通过统计每行数值单元格的占比自动识别表头行,适配不同企业的排版差异,再把多行表头内容拼接为单级列索引。
完整可运行代码
import requests from bs4 import BeautifulSoup as bs import pandas as pd url_to_use = "https://www.sec.gov/Archives/edgar/data/1000229/000095012907000818/h43371ddef14a.htm" # 添加请求头避免SEC反爬拦截 headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"} resp = requests.get(url_to_use, headers=headers) dfs = pd.read_html(resp.text, match="Salary") pd.options.display.max_columns = None df = dfs[0] # 先清理全空行/列 df.dropna(how="all", inplace = True) df.dropna(axis = 1, how="all", inplace = True) # 自动识别表头行 header_rows = [] for idx, row in df.iterrows(): # 定义有效业务数据的判断规则 def is_valid_business_data(x): if pd.isna(x): return False if isinstance(x, (int, float)): # 4位整数判定为年份,属于表头内容,不算业务数据 if 1990 <= x <= 2030 and str(x).isdigit() and len(str(x)) == 4: return False return True return False # 统计当前行有效业务数据的占比 valid_data_count = row.apply(is_valid_business_data).sum() total_non_empty = row.count() if total_non_empty > 0 and valid_data_count / total_non_empty < 0.1: header_rows.append(idx) else: # 遇到第一行有有效业务数据的行就停止识别 break # 拼接多行表头为单级列名 header_content = df.loc[header_rows].fillna('').values.T new_columns = [] for col_part_list in header_content: # 过滤空内容,用下划线拼接不同行的表头片段 merged_col_name = '_'.join([part.strip() for part in col_part_list if part.strip()]) new_columns.append(merged_col_name) # 重置表格结构:删除表头行、设置新列名 df = df.drop(header_rows).reset_index(drop=True) df.columns = new_columns # 输出处理后的表格 display(df)
适配调整说明
- 若遇到特殊排版的表格识别表头不准,可调整
valid_data_count / total_non_empty < 0.1的阈值,阈值越低,对表头行的判定越严格。 - 表头拼接的分隔符可根据需求修改,例如下划线可替换为空格、斜杠等字符。
内容的提问来源于stack exchange,提问作者xxgaryxx
相关产品推荐
相关产品推荐

