在BeautifulSoup中访问属性的问题
我在使用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 个回答
如果你的代码像你提供的那样简单,你可以用一种简洁的方式来解决它:
for x in z.findAll('el'):
print x.get('at', 'nothing')
如果你只是想通过标签名来查找一个元素,使用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
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
。