【问题标题】:How can I access namespaced XML elements using BeautifulSoup?如何使用 BeautifulSoup 访问命名空间的 XML 元素?
【发布时间】:2023-03-13 02:17:01
【问题描述】:

我有一个这样的 XML 文档:

<xml>
<web:Web>
<web:Total>4000</web:Total>
<web:Offset>0</web:Offset>
</web:Web>
</xml>

我的问题是如何使用 Python 中的 BeautifulSoup 之类的库来访问它们?

xmlDom.web["Web"].Total ?不工作?

【问题讨论】:

  • BeautifulSoup = 4.6.1 (20180728) 后已过时

标签: python xml xml-parsing beautifulsoup xml-namespaces


【解决方案1】:

BeautifulSoup 本身并不是一个 DOM 库(它没有实现 DOM API)。更复杂的是,您在该 xml 片段中使用命名空间。要解析特定的 XML 片段,您可以使用 BeautifulSoup,如下所示:

from BeautifulSoup import BeautifulSoup

xml = """<xml>
  <web:Web>
    <web:Total>4000</web:Total>
    <web:Offset>0</web:Offset>
  </web:Web>
</xml>"""

doc = BeautifulSoup( xml )
print doc.find( 'web:total' ).string
print doc.find( 'web:offset' ).string

如果您不使用命名空间,代码可能如下所示:

from BeautifulSoup import BeautifulSoup

xml = """<xml>
  <Web>
    <Total>4000</Total>
    <Offset>0</Offset>
  </Web>
</xml>"""

doc = BeautifulSoup( xml )
print doc.xml.web.total.string
print doc.xml.web.offset.string

这里的关键是 BeautifulSoup 对命名空间一无所知(或关心)。因此web:Web 被视为web:web 标记,而不是属于eweb 命名空间的Web 标记。虽然 BeautifulSoup 将 web:web 添加到 xml 元素字典中,但 python 语法不会将 web:web 识别为单个标识符。

您可以通过阅读documentation了解更多信息。

【讨论】:

  • 谢谢!现在完美运行。我总是对给 find() 提供什么感到困惑。这些命名空间定义和它们的编写方式让我很困惑...任何清除所有这些的链接都将不胜感激!
  • 只是我已经给你的文档链接......以及大量的实验。
  • AttributeError: 'NoneType' object has no attribute 'string'
【解决方案2】:

这是一个老问题,但如果您将'xml' 作为第二个参数传递给构造函数,那么至少有人可能不知道BeautifulSoup 4 确实 可以很好地处理命名空间:

soup = BeautifulSoup("""<xml>
<web:Web>
<web:Total>4000</web:Total>
<web:Offset>0</web:Offset>
</web:Web>
</xml>""", 'xml')

print soup.prettify()
<?xml version="1.0" encoding="utf-8"?>
<xml>
 <Web>
  <Total>
   4000
  </Total>
  <Offset>
   0
  </Offset>
 </Web>
</xml>

【讨论】:

  • 这对于 4.4.1-1 版本(在 ubuntu 64 16.04 中)并不完全正确。由于 cmets 是有限的。见link
【解决方案3】:

您应该使用xmlns:prefix="URI"syntax (see examples here) 在根元素上明确定义您的命名空间,然后通过 BeautifulSoup 中的prefix:tag 访问您的属性。请记住,您还应该明确定义什么,BeautifulSoup 应该如何处理您的文档,在这种情况下:

xml = BeautifulSoup(xml_content, 'xml')

【讨论】:

    【解决方案4】:

    环境

    import bs4
    bs4.__version__
    ---
    4.10.0'
    
    import sys
    print(sys.version)
    ---
    3.8.10 (default, Nov 26 2021, 20:14:08) 
    [GCC 9.3.0]
    

    带有命名空间定义的 XML 上的 BS4/XML 解析器

    from bs4 import BeautifulSoup
    
    xbrl_with_namespace = """
    <?xml version="1.0" encoding="UTF-8"?>
    <xbrl
        xmlns:dei="http://xbrl.sec.gov/dei/2020-01-31"
    >
    <dei:EntityRegistrantName>
    Hoge, Inc.
    </dei:EntityRegistrantName>
    </xbrl>
    """
    
    soup = BeautifulSoup(xbrl_with_namespace, 'xml')
    registrant = soup.find("dei:EntityRegistrantName")
    print(registrant.prettify())
    ---
    <dei:EntityRegistrantName>
    Hoge, Inc.
    </dei:EntityRegistrantName>
    

    没有命名空间定义的 XML 上的 BS4/XML 解析器

    xbrl_without_namespace = """
    <?xml version="1.0" encoding="UTF-8"?>
    <dei:EntityRegistrantName>
    Hoge, Inc.
    </dei:EntityRegistrantName>
    </xbrl>
    """
    
    soup = BeautifulSoup(xbrl_without_namespace, 'xml')
    registrant = soup.find("dei:EntityRegistrantName")
    print(registrant)
    ---
    None
    

    没有命名空间定义的 XML 上的 BS4/HTML 解析器

    BS4/HTML 解析器将&lt;namespace&gt;:&lt;tag&gt; 视为单个标签,除此之外它还降低了字母。

    soup = BeautifulSoup(xbrl_without_namespace, 'html.parser')
    registrant = soup.find("dei:EntityRegistrantName".lower()) 
    
    print(registrant)
    ---
    <dei:entityregistrantname>
    Hoge, Inc.
    </dei:entityregistrantname>
    

    与大写字母不匹配,因为它们已被转换为小写字母。

    registrant = soup.find("dei:EntityRegistrantName") 
    print(registrant)
    ---
    None
    

    结论

    1. 提供命名空间定义以将命名空间与 XML 解析器一起使用,或者
    2. 使用 HTML 解析器并处理所有小写字母。

    【讨论】:

      猜你喜欢
      • 2018-01-06
      • 2012-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多