[英]How can I find the value of elements in web scraping using BeautifulSoup?
[英]How can I access namespaced XML elements using BeautifulSoup?
我有一个 XML 文档,内容如下:
<xml>
<web:Web>
<web:Total>4000</web:Total>
<web:Offset>0</web:Offset>
</web:Web>
</xml>
我的问题是如何使用 python 中的 BeautifulSoup 之类的库访问它们?
xmlDom.web["Web"]. 总计? 不起作用?
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
标签,而不是属于web
命名空间的Web
标签。 虽然 BeautifulSoup 将web:web
添加到 xml 元素字典中,但 python 语法不会将web:web
识别为单个标识符。
您可以通过阅读文档了解更多信息。
这是一个老问题,但有人可能不知道,如果您将'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>
您应该使用xmlns:prefix="URI"
语法(请参阅此处的示例)在根元素上明确定义您的命名空间,然后通过 BeautifulSoup 中的prefix:tag
访问您的属性。 请记住,在这种情况下,您还应该明确定义 BeautifulSoup 应该如何处理您的文档:
xml = BeautifulSoup(xml_content, 'xml')
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]
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>
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
BS4/HTML 解析器将<namespace>:<tag>
视为单个标签,此外还降低了字母。
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
对于下面的示例,我假设您:
xmlns:ns_name="http://example.com"
BeautifulSoup(data, 'xml')
提取命名空间中的已知标签
如果<ns_name:tag_name>
已知,则find()
和find_all()
方法将正常工作 - 如本线程中所述。
# extract the first element with tag name
xml_soup.find('web:Web')
# extract all elements with tag name
xml_soup.find_all('web:Web')
使用 CSS 选择器在命名空间中搜索
BS4 还允许您使用前缀CSS 选择器在命名空间内进行搜索:您的命名空间,一个 pipe 符号|
最后是您的 CSS 选择器。 模板: ns_name|css_selector
。
# select all elements in the namespace 'web'
xml_soup.select('web|*')
# selecting specific elements within the namespace 'web'
xml_soup.select('web|Web > Total')
名称空间内更复杂的搜索
对于任何更复杂的事情,您需要编写自定义 boolean function:
def ns_and_regex_match(tag) -> bool:
if tag.prefix != 'web':
return False
return bool(re.search('^Off.*$', tag.name))
xml_soup.find_all(ns_and_regex_match)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.