You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python实现HTML表格转JSON:适配横向与纵向表格的优化方案求助

适配横向与纵向HTML表格转JSON的解决方案

你的核心问题在于原代码只针对“每行两个单元格组成键值对”的横向表格设计,而纵向表格存在表头行+多行数据、合并单元格(colspan/rowspan)的情况,直接按原逻辑拆分就会出现数据错位、格式混乱的问题。下面是我整理的改进方案,能同时完美适配两种表格结构:

改进后的完整代码

from bs4 import BeautifulSoup
from pathlib import Path

def parse_html_table(html_data):
    soup = BeautifulSoup(html_data, features="lxml")
    table = soup.find("table")
    if not table:
        return []
    
    # 第一步:处理合并单元格,生成完整的二维表格数据
    rows = table.find_all("tr")
    max_cols = 0
    # 先计算表格最大列数,处理colspan
    for row in rows:
        cols_count = 0
        for cell in row.find_all(["td", "th"]):
            cols_count += int(cell.get("colspan", 1))
        if cols_count > max_cols:
            max_cols = cols_count
    
    # 初始化完整表格,填充空值
    full_table = []
    for row_idx, row in enumerate(rows):
        current_row = [""] * max_cols
        col_pos = 0
        for cell in row.find_all(["td", "th"]):
            colspan = int(cell.get("colspan", 1))
            rowspan = int(cell.get("rowspan", 1))
            cell_text = cell.get_text(strip=True)
            
            # 填充当前行的colspan单元格
            for c in range(colspan):
                if col_pos + c < max_cols:
                    current_row[col_pos + c] = cell_text
            
            # 处理rowspan:给后续行的对应位置填充相同内容
            for r in range(1, rowspan):
                target_row_idx = row_idx + r
                if target_row_idx < len(rows):
                    # 确保后续行已初始化
                    while len(full_table) <= target_row_idx:
                        full_table.append([""] * max_cols)
                    if col_pos < max_cols:
                        full_table[target_row_idx][col_pos] = cell_text
            
            col_pos += colspan
        full_table.append(current_row)
    
    # 第二步:过滤空行和全空单元格,清洗数据
    cleaned_table = []
    for row in full_table:
        cleaned_row = [cell for cell in row if cell]
        if cleaned_row:
            cleaned_table.append(cleaned_row)
    
    # 第三步:判断表格类型,转换为目标JSON格式
    json_data = []
    # 判断是否为横向表格:每行固定2个单元格,是键值对结构
    is_horizontal = all(len(row) == 2 for row in cleaned_table)
    if is_horizontal:
        for row in cleaned_table:
            json_data.append({row[0]: row[1]})
    else:
        # 纵向表格:第一行是表头,后续行是对应数据
        if len(cleaned_table) < 2:
            return json_data
        headers = cleaned_table[0]
        # 转置表格,将列数据转为对应表头的行数据
        transposed_data = list(zip(*cleaned_table[1:]))
        for idx, header in enumerate(headers):
            if idx >= len(transposed_data):
                continue
            values = list(transposed_data[idx])
            # 单值存字符串,多值存列表
            json_data.append({header: values if len(values) > 1 else values[0]})
    
    return json_data

# 测试调用
html_data = Path("Table2.html").read_text()
result = parse_html_table(html_data)
print(result)

核心逻辑说明

  1. 合并单元格处理:这是解决纵向表格混乱的关键——通过解析colspanrowspan属性,把合并的单元格内容填充到对应位置,生成无缺失的完整二维表格,避免数据错位。
  2. 表格类型自动判断:通过检查每行单元格数量是否固定为2,自动识别是横向键值对表格还是纵向表头+数据表格。
  3. 纵向表格转置处理:把纵向表格的列数据转成行,让每个表头对应整列的数据,生成你需要的数组格式。
  4. 数据清洗:过滤空行和空单元格,避免无用数据干扰最终输出。

测试结果

  • 横向表格:输出完全符合你的预期格式。
  • 纵向表格:输出与你要求的一致:
[
    {'Pickup Location': 'Some Address'},
    {'Description': 'Rubics cube'},
    {'PLTS': ['1', '2']},
    {'total weight': ['20', '60']},
    {'L': ['40', '40']},
    {'W': ['40', '40']},
    {'H': ['40', '40']}
]

(如果需要统一表头大小写,可在代码里添加header.strip().title()之类的格式化处理)

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

火山引擎 最新活动