BeautifulSoup: AttributeError: 'NavigableString' object has no attribute 'children'
BeautifulSoup: AttributeError: 'NavigableString' object has no attribute 'children'
当使用 BeautifulSoup4 时,我可以 运行 此代码毫无问题地获得一个 "Shout"。当我使用 for
循环时,出现错误 AttributeError: 'NavigableString' object has no attribute 'children'
class Shout:
def __init__(self, user, msg, date):
self.user = user
self.msg = msg
self.date = date
def getShouts():
#s is a requests Session()
new_shouts = s.get(shouts_url).text
#set shouts page as parsable object
soup = BeautifulSoup(new_shouts)
shouts = []
shout_heads = soup.find_all("h2", {'class': 'A'})
shout_feet = soup.find_all("h2", {'class': 'B'})
for i in range(len(shout_heads)):
shout = Shout('', '', '')
shout.user = list(list(list(shout_heads[i].children)[0].children)[1].children)[1].get_text()
foot = shout_feet[i].get_text().split('-')
shout.msg = foot[1]
foot[2] = foot[2].split()
shout.date = foot[2][0] + " " + foot[2][1]
shouts.append(shout)
return shouts
什么会导致此错误仅在循环期间发生?
children
不仅包含元素中的标签,还包含任何 text(用 NavigableString
object 建模)。即使是空格也会导致在第一个元素之前出现文本:
<h2>
<a href="...">Some text</a>
</h2>
将有一个文本节点作为第一个 child。您必须过滤掉那些文本节点,或使用 element.find_all(True, recursive=False)
仅列出直接 child 标签。 element.find(True)
找到 first child 标签,或者 None
如果没有这样的标签。
或者您可以寻找更具体的标签,而不仅仅是第一个 child 然后是第二个 child 然后是第二个 chid;如果您有特定的标签,则只需使用它们的名称:
shout_heads[i].a.i.span.string
例如。
注意 .children
给了你一个迭代器;如果你想要一个列表,*不要在 .children
上使用 list()
。请改用 .contents
属性,它是一个列表 object.
最后但并非最不重要的一点是,当您可以直接遍历列表时,请不要使用遍历 range()
:
for shout_head in shout_heads:
shout = Shout('', '', '')
shout.user = shout_head.find(True)[0] # etc.
如果您需要合并两个列表,您可以使用 zip()
:
for shout_head, shout_foot in zip(shout_heads, shout_feet):
尽管您也可以使用 find_next_sibling()
来查找那些额外的 h2
元素,如果这些元素交替出现。
当使用 BeautifulSoup4 时,我可以 运行 此代码毫无问题地获得一个 "Shout"。当我使用 for
循环时,出现错误 AttributeError: 'NavigableString' object has no attribute 'children'
class Shout:
def __init__(self, user, msg, date):
self.user = user
self.msg = msg
self.date = date
def getShouts():
#s is a requests Session()
new_shouts = s.get(shouts_url).text
#set shouts page as parsable object
soup = BeautifulSoup(new_shouts)
shouts = []
shout_heads = soup.find_all("h2", {'class': 'A'})
shout_feet = soup.find_all("h2", {'class': 'B'})
for i in range(len(shout_heads)):
shout = Shout('', '', '')
shout.user = list(list(list(shout_heads[i].children)[0].children)[1].children)[1].get_text()
foot = shout_feet[i].get_text().split('-')
shout.msg = foot[1]
foot[2] = foot[2].split()
shout.date = foot[2][0] + " " + foot[2][1]
shouts.append(shout)
return shouts
什么会导致此错误仅在循环期间发生?
children
不仅包含元素中的标签,还包含任何 text(用 NavigableString
object 建模)。即使是空格也会导致在第一个元素之前出现文本:
<h2>
<a href="...">Some text</a>
</h2>
将有一个文本节点作为第一个 child。您必须过滤掉那些文本节点,或使用 element.find_all(True, recursive=False)
仅列出直接 child 标签。 element.find(True)
找到 first child 标签,或者 None
如果没有这样的标签。
或者您可以寻找更具体的标签,而不仅仅是第一个 child 然后是第二个 child 然后是第二个 chid;如果您有特定的标签,则只需使用它们的名称:
shout_heads[i].a.i.span.string
例如。
注意 .children
给了你一个迭代器;如果你想要一个列表,*不要在 .children
上使用 list()
。请改用 .contents
属性,它是一个列表 object.
最后但并非最不重要的一点是,当您可以直接遍历列表时,请不要使用遍历 range()
:
for shout_head in shout_heads:
shout = Shout('', '', '')
shout.user = shout_head.find(True)[0] # etc.
如果您需要合并两个列表,您可以使用 zip()
:
for shout_head, shout_foot in zip(shout_heads, shout_feet):
尽管您也可以使用 find_next_sibling()
来查找那些额外的 h2
元素,如果这些元素交替出现。