python - 使用 Beautiful Soup Python 模块将标签替换为纯文本

标签 python html-content-extraction

我正在使用 Beautiful Soup从网页中提取“内容”。我知道有人问过这个 question之前,他们都指向 Beautiful Soup,这就是我开始使用它的方式。

我能够成功获取大部分内容,但我遇到了一些挑战,这些标签是内容的一部分。 (我从一个基本策略开始:如果一个节点中有超过 x 个字符,那么它就是内容)。下面以html代码为例:

<div id="abc">
    some long text goes <a href="/"> here </a> and hopefully it 
    will get picked up by the parser as content
</div>

results = soup.findAll(text=lambda(x): len(x) > 20)

当我使用上面的代码获取长文本时,它在标签处中断(识别的文本将从'and hopefully..'开始)。所以我尝试用纯文本替换标签,如下所示:

anchors = soup.findAll('a')

for a in anchors:
  a.replaceWith('plain text')

上面的代码不起作用,因为 Beautiful Soup 将字符串作为 NavigableString 插入,当我将 findAll 与 len(x) > 20 一起使用时会导致同样的问题。我可以先使用正则表达式将 html 解析为纯文本,清除所有不需要的标签,然后调用 Beautiful Soup。但我想避免两次处理相同的内容——我正在尝试解析这些页面,以便我可以显示给定链接的内容片段(非常像 Facebook 分享)——如果一切都用 Beautiful Soup 完成,我想它会更快。

所以我的问题是:有没有一种方法可以使用 Beautiful Soup 来“清除标签”并将它们替换为“纯文本”。如果没有,最好的方法是什么?

感谢您的建议!

更新 Alex 的代码在示例中运行良好。我还尝试了各种边缘情况,它们都运行良好(经过以下修改)。所以我在现实生活中的网站上试了一下,但遇到了让我困惑的问题。

import urllib
from BeautifulSoup import BeautifulSoup

page = urllib.urlopen('http://www.engadget.com/2010/01/12/kingston-ssdnow-v-dips-to-30gb-size-lower-price/')

anchors = soup.findAll('a')
i = 0
for a in anchors:
    print str(i) + ":" + str(a)
    for a in anchors:
        if (a.string is None): a.string = ''
        if (a.previousSibling is None and a.nextSibling is None):
            a.previousSibling = a.string
        elif (a.previousSibling is None and a.nextSibling is not None):
            a.nextSibling.replaceWith(a.string + a.nextSibling)
        elif (a.previousSibling is not None and a.nextSibling is None):
            a.previousSibling.replaceWith(a.previousSibling + a.string)
        else:
            a.previousSibling.replaceWith(a.previousSibling + a.string + a.nextSibling)
            a.nextSibling.extract()
    i = i+1

当我运行上面的代码时,出现以下错误:

0:<a href="http://www.switched.com/category/ces-2010">Stay up to date with 
Switched's CES 2010 coverage</a>
Traceback (most recent call last):
  File "parselink.py", line 44, in <module>
  a.previousSibling.replaceWith(a.previousSibling + a.string + a.nextSibling)
 TypeError: unsupported operand type(s) for +: 'Tag' and 'NavigableString'

当我查看 HTML 代码时,'Stay up to date..' 没有任何 previous sibling 姐妹(我不知道 previous sibling 姐妹是如何工作的,直到我看到 Alex 的代码并且根据我的测试它看起来像是在寻找标记前的“文本”)。所以,如果没有 previous sibling 姐妹,我很惊讶它没有通过 a.previousSibling is None 和 a;nextSibling is None 的 if 逻辑。

你能告诉我我做错了什么吗?

-ecognium

最佳答案

适用于您的特定示例的方法是:

from BeautifulSoup import BeautifulSoup

ht = '''
<div id="abc">
    some long text goes <a href="/"> here </a> and hopefully it 
    will get picked up by the parser as content
</div>
'''
soup = BeautifulSoup(ht)

anchors = soup.findAll('a')
for a in anchors:
  a.previousSibling.replaceWith(a.previousSibling + a.string)

results = soup.findAll(text=lambda(x): len(x) > 20)

print results

发射

$ python bs.py
[u'\n    some long text goes  here ', u' and hopefully it \n    will get picked up by the parser as content\n']

当然,您可能需要多加注意,即,如果没有 a.string 怎么办? ,或者如果 a.previousSiblingNone -- 你需要合适的 if声明来处理这种极端情况。但我希望这个总体思路可以帮助你。 (事实上​​ ,如果 next 兄弟是一个字符串,您可能希望合并它 - 不确定它如何与您的启发式算法一起使用 len(x) > 20 ,但例如说您有两个 9 个字符的字符串,<a> 中间包含一个 5 个字符的字符串,也许你想把这批货当作“23 个字符的字符串”?我不知道,因为我不知道了解启发式的动机)。

我想除了<a>您还需要删除其他标签,例如 <b><strong> , 也许 <p>和/或 <br> , ETC...?我想这也取决于您的启发式背后的实际想法是什么!

关于python - 使用 Beautiful Soup Python 模块将标签替换为纯文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2061718/

相关文章:

python - TensorFlow 变量无法初始化

python - 如何追踪这个?属性错误 : 'NoneType' object has no attribute 'is_relation' during makemigrations

python - 使用 BeautifulSoup 根据内容值提取标签内容

html - 在 django 中允许基本的 html 标记

从格式错误的 html 页面中提取文本的 Python 策略

python - 无法 reshape numpy 数组

python - 如何使用Python的shutil将文件复制到包含&符号 '&'的路径?

python - 如何在 Python 中将 dict 绑定(bind)到准备好的 Cassandra 语句?

java - 可以解析 HTML 文档并构建 DOM 树(java)

html - 从 HTML 文档中抓取最大的文本 block