美丽的汤提取物标签删除文本

时间:2017-01-13 18:18:36

标签: python html web-scraping beautifulsoup

我正在尝试使用Beautifuloup来提取html标签并删除文本。例如,拿这个html:

html_page = """
<html>
<body>
<table>
<tr class=tb1><td>Lorem Ipsum dolor Sit amet</td></tr>
<tr class=tb1><td>Consectetuer adipiscing elit</td></tr>
<tr><td>Aliquam Tincidunt mauris eu Risus</td></tr>
<tr><td>Vestibulum Auctor Dapibus neque</td></tr>
</table>
</body>
</html>
"""

期望的结果是:

<html>
<body>
<table>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
</table>
</body>
</html>

这是我到目前为止所得到的:

def get_tags(soup):
    copy_soup = soup
    for tag in copy_soup.findAll(True):
        tag.attrs = {} # removes attributes of a tag
        tag.string = ''

    return copy_soup

print get_tags(soup)

使用tag.attrs = {}可以删除所有标记属性。但是当我尝试使用tag.string或tag.clear()时,我只剩下<html></html>。我理解可能发生的事情是在使用tag.stringtag.clear()的第一次迭代中删除html标记内的所有内容。

我不确定如何解决这个问题。也许先递归删除孩子的文字?或者,我缺少一种更简单的方法吗?

2 个答案:

答案 0 :(得分:1)

您不能简单地将.string重置为空字符串,因为如果某个元素有一个包含文本的子项,例如示例中的tr元素,则会无意中删除td个元素从树上。

您不能使用.clear(),因为它也会递归删除所有子节点。

我不记得在没有BeautifulSoup数据的情况下获取HTML树结构的内置方法 - 我使用以下方法:

for elm in soup.find_all():
    if not elm.find(recursive=False):  # if not children
        elm.string = ''
    elm.attrs = {}

我们只在没有孩子的情况下重置.string

演示:

>>> from bs4 import BeautifulSoup
>>> 
>>> html_page = """
... <html>
... <body>
... <table>
... <tr class=tb1><td>Lorem Ipsum dolor Sit amet</td></tr>
... <tr class=tb1><td>Consectetuer adipiscing elit</td></tr>
... <tr><td>Aliquam Tincidunt mauris eu Risus</td></tr>
... <tr><td>Vestibulum Auctor Dapibus neque</td></tr>
... </table>
... </body>
... </html>
... """
>>> 
>>> soup = BeautifulSoup(html_page, "html.parser")
>>> for elm in soup.find_all():
...     if not elm.find(recursive=False):
...         elm.string = ''
...     elm.attrs = {}
... 
>>> print(soup.prettify())
<html>
 <body>
  <table>
   <tr>
    <td>
    </td>
   </tr>
   <tr>
    <td>
    </td>
   </tr>
   <tr>
    <td>
    </td>
   </tr>
   <tr>
    <td>
    </td>
   </tr>
  </table>
 </body>
</html>

答案 1 :(得分:1)

实际上,我能够通过递归更新子标签来删除文本。您还可以在递归中更新其属性。

from bs4 import BeautifulSoup
from bs4.element import NavigableString

def delete_displayed_text(element):
    """
    delete displayed text from beautiful soup tag element object recursively
    :param element: beautiful soup tag element object
    :return: beautiful soup tag element object
    """
    new_children = []
    for child in element.contents:
        if not isinstance(child, NavigableString):
            new_children.append(delete_displayed_text(child))
    element.contents = new_children
    return element

if __name__ =='__main__':
    html_code_sample = '<div class="hello">I am not supposed to be displayed<a>me neither</a></div>'
    soup = BeautifulSoup(html_code_sample, 'html.parser')
    soup = delete_displayed_text(soup)
    cleaned_soup = BeautifulSoup(str(soup), 'html.parser')
    print(cleaned_soup.getText())