我正在尝试使用BeautifulSoup创建一个通用的刮刀,我试图检测直接文本可用的标记。
考虑这个例子:
<body>
<div class="c1">
<div class="c2">
<div class="c3">
<div class="c4">
<div class="c5">
<h1> A heading for section </h1>
</div>
<div class="c5">
<p> Some para </p>
</div>
<div class="c5">
<h2> Sub heading </h2>
<p> <span> Blah Blah </span> </p>
</div>
</div>
</div>
</div>
</div>
</body>
这里我的目标是提取(带有类c4的div)因为它具有所有文本内容。在它之前的其余部分c1 - c3对我来说只是包装。
识别节点的一种可能方法是,我想出来了:
if node.find(re.compile("^h[1-6]"), recursive=False) is not None:
return node.parent.parent
但这种情况太具体了。
是否有任何优化的方法可以在一个递归级别中查找文本。即如果我做了像
这样的事情node.find(text=True, recursion_level=1)
然后它应该只考虑直接的孩子而返回文本。
到目前为止我的解决方案,不确定它是否适用于所有情况。
def check_for_text(node):
return node.find(text=True, recursive=False)
def check_1_level_depth(node):
if check_for_text(node):
return check_for_text(node)
return map(check_for_text, node.children)
对于上面的代码:node是当前正在检查的汤元素,即div,span等。 请假设我正在处理check_for_text()中的所有异常(AttributeError:'NavigableString')
答案 0 :(得分:2)
原来我必须写一个递归函数来消除一个孩子的标签。这是代码:
# Pass soup.body in following
def process_node(node):
if type(node) == bs4.element.NavigableString:
return node.text
else:
if len(node.contents) == 1:
return process_node(node.contents[0])
elif len(node.contents) > 1:
return map(process_node, node.children)
到目前为止,它运作良好且快速。
答案 1 :(得分:0)
我认为你需要的是这样的:
bs = BeautifulSoup(html)
all = bs.findAll()
previous_elements = []
found_element = None
for i in all:
if not i.string:
previous_elements.append(i)
else:
found_element = i
break
print("previous:")
for i in previous_elements:
print(i.attrs)
print("found:")
print(found_element)
输出:
previous:
{}
{'class': ['c1']}
{'class': ['c2']}
{'class': ['c3']}
{'class': ['c4']}
found:
<h1> A heading for section </h1>