【问题标题】:Find All Elements Given Namespaced Attribute查找给定命名空间属性的所有元素
【发布时间】:2013-03-06 09:48:08
【问题描述】:

如果我有这样的事情:

<p>blah</p>
<p foo:bar="something">blah</p>
<p foo:xxx="something">blah</p>

如何让 beautifulsoup 选择具有 foo 命名空间属性的元素?

例如我想返回第二个和第三个 p 元素。

【问题讨论】:

    标签: python xml beautifulsoup


    【解决方案1】:

    来自documentation

    Beautiful Soup 提供了一个名为 attrs 的特殊参数,您可以在这些情况下使用它。 attrs 是一个类似于关键字参数的字典:

    soup.findAll(id=re.compile("para$"))
    # [<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,
    #  <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
    
    soup.findAll(attrs={'id' : re.compile("para$")})
    # [<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,
    #  <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
    

    如果需要对名称为 Python 保留字的属性(如 class、for 或 import)进行限制,可以使用 attrs;或名称是 Beautiful Soup 搜索方法的非关键字参数的属性:名称、递归、限制、文本或 attrs 本身。

    from BeautifulSoup import BeautifulStoneSoup
    xml = '<person name="Bob"><parent rel="mother" name="Alice">'
    xmlSoup = BeautifulStoneSoup(xml)
    
    xmlSoup.findAll(name="Alice")
    # []
    
    xmlSoup.findAll(attrs={"name" : "Alice"})
    # [parent rel="mother" name="Alice"></parent>]
    

    所以对于你给定的例子:

    soup.findAll(attrs={ "foo" : re.compile(".*") })
    # or
    soup.findAll(attrs={ re.compile("foo:.*") : re.compile(".*") })
    

    【讨论】:

      【解决方案2】:

      BeautifulSoup(版本 3 和 4)似乎没有将命名空间前缀视为任何特殊内容。它只是将命名空间前缀和命名空间属性视为名称中恰好有冒号的属性。

      因此要在foo 命名空间中查找具有属性的&lt;p&gt; 元素,您只需遍历所有属性键并检查是否attr.startswith('foo')

      import BeautifulSoup as bs
      content = '''\
      <p>blah</p>
      <p foo:bar="something">blah</p>
      <p foo:xxx="something">blah</p>'''
      
      soup = bs.BeautifulSoup(content)
      for p in soup.find_all('p'):
          for attr in p.attrs.keys():
              if attr.startswith('foo'):
                  print(p)
                  break
      

      产量

      <p foo:bar="something">blah</p>
      <p foo:xxx="something">blah</p>
      

      使用lxml,您可以通过 XPath 进行搜索,它确实支持按命名空间搜索属性的语法:

      import lxml.etree as ET
      content = '''\
      <root xmlns:foo="bar">
      <p>blah</p>
      <p foo:bar="something">blah</p>
      <p foo:xxx="something">blah</p></root>'''
      
      root = ET.XML(content)
      for p in root.xpath('p[@foo:*]', namespaces={'foo':'bar'}):
          print(ET.tostring(p))
      

      产量

      <p xmlns:foo="bar" foo:bar="something">blah</p>
      <p xmlns:foo="bar" foo:xxx="something">blah</p>
      

      【讨论】:

      • 是否可以匹配一个属性的开头,所以任何以 foo: 开头的属性?我已按问题编辑。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多