在BeautifulSoup中访问属性的问题

6 投票
4 回答
5586 浏览
提问于 2025-04-16 16:45

我在使用Python(2.7)时遇到了一些问题。我的代码大致是这样的:

str = '<el at="some">ABC</el><el>DEF</el>'
z = BeautifulStoneSoup(str)

for x in z.findAll('el'):
    # if 'at' in x:
    # if hasattr(x, 'at'):
        print x['at']   
    else:
        print 'nothing'

我原本以为第一个if语句会正常工作(也就是说,如果at不存在,就打印"nothing"),但它总是打印“什么都没有”(也就是总是False)。而第二个if语句则总是True,这会导致代码在尝试从第二个<el>元素中访问at时抛出一个KeyError错误,因为这个元素当然是不存在的。

4 个回答

1

如果你的代码像你提供的那样简单,你可以用一种简洁的方式来解决它:

for x in z.findAll('el'):
    print x.get('at', 'nothing')
1

如果你只是想通过标签名来查找一个元素,使用pyparsing这个工具可能会更简单易懂,而且不会用到一些已经不推荐使用的API,比如has_key

from pyparsing import makeXMLTags

# makeXMLTags creates a pyparsing expression that matches tags with
# variations in whitespace, attributes, etc.
el,elEnd = makeXMLTags('el')

# scan the input text and work with elTags
for elTag, tagstart, tagend in el.scanString(xmltext):
    if elTag.at:
        print elTag.at

另外,pyparsing还允许你定义一个过滤的解析动作,这样标签只有在找到特定的属性值(或者任何值的属性)时才会匹配,这样可以让查找更加精确。

# import parse action that will filter by attribute
from pyparsing import withAttribute

# only match el tags having the 'at' attribute, with any value
el.setParseAction(withAttribute(at=withAttribute.ANY_VALUE))

# now loop again, but no need to test for presence of 'at'
# attribute - there will be no match if 'at' is not present
for elTag, tagstart, tagend in el.scanString(xmltext):
    print elTag.at
7

in 操作符是用来检查序列和映射类型的,你怎么会觉得 BeautifulSoup 返回的对象应该正确实现这个操作呢?根据 BeautifulSoup 的文档,你应该使用 [] 语法来访问属性。

关于 hasattr,我觉得你把 HTML/XML 属性和 Python 对象属性搞混了。hasattr 是用来检查后者的,而据我所知,BeautifulSoup 并不会把它解析的 HTML/XML 属性反映到它自己的对象属性中。

顺便说一下,BeautifulSoup 中的 Tag 对象确实实现了 __contains__,所以也许你用错了对象?你能给我一个完整但简单的例子来展示这个问题吗?


运行这个:

from BeautifulSoup import BeautifulSoup

str = '<el at="some">ABC</el><el>DEF</el>'
z = BeautifulSoup(str)

for x in z.findAll('el'):
    print type(x)
    print x['at']

我得到了:

<class 'BeautifulSoup.Tag'>
some
<class 'BeautifulSoup.Tag'>
Traceback (most recent call last):
  File "soup4.py", line 8, in <module>
    print x['at']
  File "C:\Python26\lib\site-packages\BeautifulSoup.py", line 601, in __getitem__
    return self._getAttrMap()[key]
KeyError: 'at'

这正是我预期的。第一个 el 有一个 at 属性,第二个没有 - 这就抛出了一个 KeyError


更新 2:BeautifulSoup.Tag.__contains__ 是查看标签的 内容,而不是它的属性。要检查一个属性是否存在,使用 in

撰写回答