如何使用BeautifulSoup仅提取不属于其他div子元素的顶层父div
问题背景
我手头有若干HTML文件,针对每个文件我需要逐个抓取所有表格,同时保留表格的索引,用于获取表格对应的标题及表格前的部分文本。
此前我使用soup.find_all('divs')提取所有div元素并基于该结果搭建了我的应用。但我测试另一种格式略有不同的HTML文件时出现了问题,该文件代码示例如下:
<div style="margin-top:27.85pt;margin-bottom:21.86pt;margin-left:69.66pt;width:456pt;"> <div style="text-align:center; width:456pt; line-height:14pt;font-weight:bold;color:#33058D;font-size:12pt;">UNITED STATES<br/>SECURITIES AND EXCHANGE COMMISSION<br/>Washington, D.C. 20549<font style="font-weight:normal;color:#3D3935;font-family:Times New Roman, Times, serif ;letter-spacing:0.24pt;"> </font></div> <div style="margin-top:12pt; text-align:center; width:456pt; line-height:14pt;font-weight:bold;color:#33058D;font-size:12pt;">SCHEDULE 14A<font style="font-weight:normal;"> </font></div> <div style="margin-top:8pt; text-align:center; width:456pt; line-height:11pt;">Proxy Statement Pursuant to Section 14(a) of <br/>the Securities Exchange Act of 1934<font style="font-family:Times New Roman, Times, serif ;letter-spacing:0.18pt;"> </font></div> </div>
该HTML结构包含1个父div和3个嵌套在其内部的子div,调用soup.find_all('div')会返回4个结果:包含子元素的父div,以及该父div下的每一个子div。
而我仅需要提取顶层的父div。我尝试编写了如下代码实现该需求:
divs = [] while len(html) > 0: soup = BeautifulSoup(html, 'lxml') div = soup.find('div') divs.append(div) length = len(str(div)) html = html[:len(html)-length]
虽然上述代码返回的结果完全符合我的预期,但运行效率极低,需要耗费很长时间才能执行完毕,请问有没有更高效的实现方案?
优化方案
原代码效率极低的核心原因是每次循环都重新解析剩余HTML字符串、反复生成BeautifulSoup对象,同时频繁做长字符串切片,大文件场景下开销会成倍增长。
可以直接通过BeautifulSoup自带的过滤规则实现需求,仅需解析一次HTML即可得到结果,效率提升明显,两种常用实现如下:
- 方案1:如果顶层div均为
<body>标签的直接子元素,直接关闭递归查找即可
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') # recursive=False 代表仅查找目标节点的直接子元素,不会深入嵌套层级检索 top_divs = soup.body.find_all('div', recursive=False)
- 方案2:如果顶层div可能包裹在其他非div标签(如section、article)中,可自定义过滤规则
def is_top_level_div(tag): # 匹配div标签,且父节点不是div标签 return tag.name == 'div' and tag.parent.name != 'div' top_divs = soup.find_all(is_top_level_div)
两种方案返回结果和原实现完全一致,对于MB级以上的大HTML文件,执行速度可从分钟级降至毫秒级。
内容的提问来源于stack exchange,提问作者Mahmoud Embaby
相关产品推荐
相关产品推荐

