【问题标题】:Extracting tag content based on content value using BeautifulSoup使用 BeautifulSoup 根据内容值提取标签内容
【发布时间】:2012-02-13 03:12:41
【问题描述】:

我有一个如下格式的 Html 文档。

<p>&nbsp;&nbsp;&nbsp;1. Content of the paragraph <i> in italic </i> but not <b> strong </b> <a href="url">ignore</a>.</p>

我想提取段落标签的内容,包括斜体和粗体标签的内容,但不包括锚标签的内容。此外,可以忽略开头的数字。

预期的输出是: 段落内容为斜体,但不强。

最好的方法是什么?

另外,以下代码 sn-p 返回 TypeError: argument of type 'NoneType' is not iterable

soup = BSoup(page)
for p in soup.findAll('p'):
    if '&nbsp;&nbsp;&nbsp;' in p.string:
        print p

感谢您的建议。

【问题讨论】:

    标签: python beautifulsoup html-content-extraction


    【解决方案1】:

    您的代码失败,因为如果标签只有一个孩子并且该孩子是NavigableString,则设置了tag.string

    你可以通过提取a标签来实现你想要的:

    from BeautifulSoup import BeautifulSoup
    
    s = """<p>&nbsp;&nbsp;&nbsp;1. Content of the paragraph <i> in italic </i> but not <b> strong </b> <a href="url">ignore</a>.</p>"""
    soup = BeautifulSoup(s, convertEntities=BeautifulSoup.HTML_ENTITIES)
    
    for p in soup.findAll('p'):
        for a in p.findAll('a'):
            a.extract()
        print ''.join(p.findAll(text=True))
    

    【讨论】:

    • 太棒了,感谢您的明确回复。它就像魅力一样。
    【解决方案2】:

    您遇到的关于string 的问题是因为stringdocumentation 中所述,仅可用:

    如果一个标签只有一个子节点,并且该子节点是一个字符串

    因此,在您的情况下,p.stringNone,您无法对其进行迭代。要访问标签内容,您必须使用p.contents(这是一个包含标签的列表)或p.text(这是一个删除了所有标签的字符串)。

    在你的情况下,你可能正在寻找这样的东西:

    >>> ''.join([str(e) for e in soup.p.contents
                        if not isinstance(e, BeautifulSoup.Tag)
                           or e.name != 'a'])
    >>> '&nbsp;&nbsp;&nbsp;1. Content of the paragraph <i> in italic </i> but not <b> strong </b> .'
    

    如果您还需要删除 `' ' 前缀,我会使用正则表达式从最终字符串中删除该部分。

    【讨论】:

    • 感谢 jcollado 的快速回复。文档参考和您的解释很有启发性。
    【解决方案3】:

    我认为您只需要遍历p 中的标签并收集所需的字符串。

    使用lxml,您可以使用XPath:

    import lxml.html as LH
    import re
    
    content = '''\
    <p>&nbsp;&nbsp;&nbsp;1. Content of the paragraph <i> in italic </i> but not <b> strong </b> <a href="url">ignore</a>.</p>'''
    
    doc = LH.fromstring(content)
    ptext = ''.join(doc.xpath('//p/descendant-or-self::*[not(self::a)]/text()'))
    pat = r'^.*\d+.\s*'
    print(re.sub(pat,'',ptext))
    

    产量:

    Content of the paragraph  in italic  but not  strong  .
    

    【讨论】:

    • 感谢 unutbu 的回复。消除前缀数字的正则表达式非常有用。我在 BeautifulSoup 本身中得到了答案,所以不需要使用 lxml,但是,感谢您提供有关它的信息。
    【解决方案4】:

    http://www.crummy.com/software/BeautifulSoup/bs4/doc/#get-text

    如果您只想要文档或标签的文本部分,可以使用 get_text() 方法。它以单个 Unicode 字符串的形式返回文档中或标签下的所有文本。 (在上面链接中的文档中给出)

    【讨论】:

      猜你喜欢
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多