Python爬虫实战:把Bootstrap栅格Div伪表格转为原生Table表格

前言

做爬虫抓取网页的时候经常会遇到一类页面:网页并不是传统的<table>表格,而是用Bootstrap的row+col-md‑ div布局模拟出来的表格*。

浏览器打开网页依靠Bootstrap CSS样式,div可以整齐排列成表格模样。但是当我们把HTML片段扒取保存下来之后,问题就来了:

  1. 保存到本地的HTML片段,脱离原网站环境,拿不到Bootstrap样式;
  2. 内网服务器环境,无法访问外网CDN加载css;
  3. 就算正则把visible-md这类响应式class删掉,没有栅格样式,所有div全部垂直堆叠挤在一起,完全看不出表格结构。

核心痛点:div栅格表格强依赖外部CSS,爬虫归档、数据预览场景非常不友好。

最优方案:在Python里把div伪表格解析,重新生成原生HTML <table>。原生table自带边框布局,不依赖任何外部样式,断网、内网打开都能正常查看。

原始页面结构长什么样

网页源码类似下面这种结构:

复制代码
<!--表头 -->
<div class="row structure">
    <div class="boxs">
        <div class="col-md‑1">序号</div>
        <div class="col-md‑2">标准编号</div>
        <div class="col-md‑2">项目名称</div>
    </div>
</div>
<!--数据行 -->
<div class="row">
    <div class="structurewords">
        <div class="col-md‑1"><span>1</span></div>
        <div class="col-md‑2">GB 50017‑2003</div>
        <div class="col-md‑2">钢结构设计规范</div>
    </div>
</div>

没有<table><tr><td>标签,全部靠div+CSS实现表格效果。

实现思路

  1. 使用lxml.etree解析抓取到的HTML字符串;
  2. XPath定位表头节点:row structure下面的.boxs,提取内部div文本作为<th>表头;
  3. XPath定位所有数据行节点:div.structurewords,每一个对应表格一行<tr>
  4. 遍历行内子div,提取文本作为<td>单元格;
  5. 程序动态构建完整table DOM,设置边框、合并单元格样式;
  6. 序列化为完整HTML文档返回,输出可以直接保存打开。

重要:不要使用正则表达式解析HTML!HTML不是规则文本,正则处理嵌套、转义、异常标签很容易出错,优先使用lxml DOM解析。

完整Python代码实现

入参是爬虫拿到的HTML字符串片段,返回完整的table页面字符串。

复制代码
from lxml import etree

def convert_div_to_table_html(content_html: str) -> str:
    """
    将bootstrap div栅格伪表格,转换为原生table完整html
    :param content_html: 抓取得到的div片段html字符串
    :return: 完整可直接打开的html文档字符串,原生table,无外部css依赖
    """
    tree = etree.HTML(content_html)

    # 构建原生table,设置基础表格样式
    table = etree.Element("table")
    table.attrib["border"] = "1"
    table.attrib["cellpadding"] = "6"
    table.attrib["cellspacing"] = "0"
    table.attrib["style"] = "border‑collapse:collapse;width:100%;"

    thead = etree.SubElement(table, "thead")
    tbody = etree.SubElement(table, "tbody")

    # 解析表头
    header_box = tree.xpath('//div[contains(@class,"row") and contains(@class,"structure")]//div[@class="boxs"]')
    if header_box:
        tr_head = etree.SubElement(thead, "tr")
        for col_div in header_box[0].xpath("./div"):
            text = "".join(col_div.xpath(".//text()")).strip()
            th = etree.SubElement(tr_head, "th")
            th.text = text

    # 解析全部数据行 structurewords
    row_nodes = tree.xpath('//div[@class="structurewords"]')
    for row_div in row_nodes:
        tr = etree.SubElement(tbody, "tr")
        for cell_div in row_div.xpath("./div"):
            cell_text = "".join(cell_div.xpath(".//text()")).strip()
            td = etree.SubElement(tr, "td")
            td.text = cell_text

    table_str = etree.tostring(table, method="html", encoding="utf‑8").decode("utf‑8")

    full_html = f'''<!DOCTYPE html>
<html lang="zh‑CN">
<head>
<meta charset="UTF‑8">
<title>表格预览</title>
</head>
<body>
{table_str}
</body>
</html>
'''
    return full_html

# 测试示例
if __name__ == "__main__":
    # 这里替换成你爬虫获取的div html片段
    raw_div_html = """你的div片段html"""
    result_html = convert_div_to_table_html(raw_div_html)
    with open("table_output.html", "w", encoding="utf‑8") as f:
        f.write(result_html)

爬虫项目中的实际调用场景

爬虫中,我们抓取多页数据,循环拼接每一页div html字符串,再调用转换函数:

复制代码
# 循环拼接多页div片段
content_html = ""
for tag in content_list:
    temp = etree.tostring(tag, method="html", encoding="utf‑8").decode("utf‑8")
    content_html += temp

# 把div字符串转为原生table完整html
content_html = convert_div_to_table_html(content_html)

# 存入item入库
item["content_html"] = content_html
item["html"] = content_html

踩坑总结

  1. ❌ 不要仅删除visible‑md / hidden‑sm这类class:只是移除显示隐藏标记,依旧依赖Bootstrap栅格CSS,内网/断网环境直接布局错乱;
  2. ❌ 不要使用正则解析HTML DOM,正则无法处理标签嵌套、属性顺序变化;
  3. ✅ lxml DOM解析是可靠方案,直接解析语义节点,不依赖class样式;
  4. ✅ 输出原生table之后,零外部样式依赖,浏览器本地双击直接打开就能看到带边框整齐表格;
  5. 注意:提取文本使用"".join(node.xpath('.//text()')),可以把span嵌套里面的文本完整取出。

适用与不适用场景

✅ 适合场景:

  • 爬虫网页归档存储,内网环境预览表格;
  • 原始页面使用Bootstrap div模拟表格;
  • 希望输出离线可用的表格HTML。

❌ 不适合场景:

  • 页面是真正原生<table>表格;
  • div布局结构和示例差异很大(需要调整xpath表达式适配页面)。

小结

很多网站为了移动端适配,大量使用div栅格代替传统table。爬虫直接保存div片段会遇到样式丢失的大坑。

处理思路不要停留在修改class、引入CDN样式,从DOM层面重新构建原生table才是治本的办法,生成的结果兼容性最好,非常适合爬虫系统入库归档。

相关推荐
“AI国潮设计-小江”2 小时前
【SDXL实战】Python自动化生成3D潮汕美食IP,附ComfyUI工作流与商用变现思路
开发语言·人工智能·python·prompt·aigc
tellmewhoisi2 小时前
python的鬼畜写法(从js角度看)
python
夜雪一千2 小时前
如何使用Python的BeautifulSoup库来处理HTML
python
傻啦嘿哟2 小时前
某新闻平台爬虫:爬取各频道新闻,分析媒体传播规律
python
鹿角片ljp2 小时前
Prompt Cache、Token 成本与 Plan Compiler 的工程设计
java·python·算法
麻雀飞吧11 小时前
先判断工具用来学习、开发还是执行
人工智能·python
人邮异步社区11 小时前
学习Python的最佳学习路径是什么?
python·程序员
troy12813 小时前
Python 基础语法(九):Django/Flask/FastAPI 三大 Web 框架详细对比解析
python·jupyter·django·flask·github·fastapi
jzshmyt13 小时前
我用 Python 从零“生成“了一个宇宙,然后让它观察自己(v14)
人工智能·pytorch·python·numpy·matplotlib·空间计算·scipy