Searching Within the Parse Tree
上面说明的方法findAll
及find
,都是从剖析树的某一点开始并一直往下。 他们反复的遍历对象的contents
直到最低点。
也就是说你不能在 NavigableString
对象上使用这些方法, 因为NavigableString
没有contents:它们是剖析树的叶子。
[这段翻译的不太准确]但是向下搜索不是唯一的遍历剖析树的方法。在Navigating剖析树 中,我们可以使用这些方法:parent
, nextSibling
等。 他们都有2个相应的方法:一个类似findAll
,一个类似find
. 由于NavigableString
对象也支持这些方法,你可以像Tag
一样 使用这些方法。
为什么这个很有用?因为有些时候,你不能使用findAll
或find
从Tag
或NavigableString
获得你想要的。例如,下面的HTML文档:
from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup('''<ul>
<li>An unrelated list
</ul>
<h1>Heading</h1>
<p>This is <b>the list you want</b>:</p>
<ul><li>The data you want</ul>''')
有很多方法去定位到包含特定数据的<LI> 标签。最明显的方式如下:
soup('li', limit=2)[1]
# <li>The data you want</li>
显然,这样获得所需的<LI>标签并不稳定。如果,你只分析一次页面,这没什么影响。 但是如果你需要在一段时间分析很多次这个页面,就需要考虑一下这种方法。 If the irrelevant list grows another <LI> tag, you'll get that tag instead of the one you want, and your script will break or give the wrong data.
因为如果列表发生变化,你可能就得不到你想要的结果。
soup('ul', limit=2)[1].li
# <li>The data you want</li>
That's is a little better, because it can survive changes to the irrelevant list. But if the document grows another irrelevant list at the top, you'll get the first <LI> tag of that list instead of the one you want. A more reliable way of referring to the ul tag you want would better reflect that tag's place in the structure of the document.
这有一点好处,因为那些不相干的列表的变更生效了。 但是如果文档增长的不相干的列表在顶部,你会获得第一个<LI>标签而不是 你想要的标签。一个更可靠的方式是去引用对应的ul标签, 这样可以更好的处理文档的结构。
在HTML里面,你也许认为你想要的list是<H1>标签下的<UL>标签。 问题是那个标签不是在<H1>下,它只是在它后面。获得<H1>标签很容易,但是获得 <UL>却没法使用first
和fetch
, 因为这些方法只是搜索<H1>标签的contents
。 你需要使用next
或nextSibling
来获得<UL>标签。
s = soup.h1
while getattr(s, 'name', None) != 'ul':
s = s.nextSibling
s.li
# <li>The data you want</li>
或者,你觉得这样也许会比较稳定:
s = soup.find(text='Heading')
while getattr(s, 'name', None) != 'ul':
s = s.next
s.li
# <li>The data you want</li>
但是还有很多困难需要你去克服。这里会介绍一下非常有用的方法。 你可以在你需要的使用它们写一些遍历成员的方法。它们以某种方式遍历树,并跟踪那些满足条件的Tag
和NavigableString
对象。代替上面那个例子的第一的循环的代码,你可以这样写:
soup.h1.findNextSibling('ul').li
# <li>The data you want</li>
第二循环,你可以这样写:
soup.find(text='Heading').findNext('ul').li
# <li>The data you want</li>
这些循环代替调用findNextString
和findNext
。 本节剩下的内容是这种类型所用方法的参考。同时,对于遍历总是有两种方法: 一个是返回list的findAll
,一个是返回单一量的find
。
下面,我们再举一个例子来说明:
from BeautifulSoup import BeautifulSoup
doc = ['<html><head><title>Page title</title></head>',
'<body><p id="firstpara" align="center">This is paragraph <b>one</b>.',
'<p id="secondpara" align="blah">This is paragraph <b>two</b>.',
'</html>']
soup = BeautifulSoup(''.join(doc))
print soup.prettify()
# <html>
# <head>
# <title>
# Page title
# </title>
# </head>
# <body>
# <p id="firstpara" align="center">
# This is paragraph
# <b>
# one
# </b>
# .
# </p>
# <p id="secondpara" align="blah">
# This is paragraph
# <b>
# two
# </b>
# .
# </p>
# </body>
# </html>
findNextSiblings(name, attrs, text, limit, **kwargs)
and findNextSibling(name, attrs, text, **kwargs)
这两个方法以nextSibling
的成员为依据, 获得满足条件的Tag
或NavigableText
对象。 以上面的文档为例:
paraText = soup.find(text='This is paragraph ')
paraText.findNextSiblings('b')
# [<b>one</b>]
paraText.findNextSibling(text = lambda(text): len(text) == 1)
# u'.'
findPreviousSiblings(name, attrs, text, limit, **kwargs)
and findPreviousSibling(name, attrs, text, **kwargs)
这两个方法以previousSibling
成员为依据,获得满足条件的Tag
和 NavigableText
对象。 以上面的文档为例:
paraText = soup.find(text='.')
paraText.findPreviousSiblings('b')
# [<b>one</b>]
paraText.findPreviousSibling(text = True)
# u'This is paragraph '
findAllNext(name, attrs, text, limit, **kwargs)
and findNext(name, attrs, text, **kwargs)
这两个方法以next
的成员为依据, 获得满足条件的Tag
和NavigableText
对象。 以上面的文档为例:
pTag = soup.find('p')
pTag.findAllNext(text=True)
# [u'This is paragraph ', u'one', u'.', u'This is paragraph ', u'two', u'.']
pTag.findNext('p')
# <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>
pTag.findNext('b')
# <b>one</b>
findAllPrevious(name, attrs, text, limit, **kwargs)
and findPrevious(name, attrs, text, **kwargs)
这两方法以previous
的成员依据, 获得满足条件的Tag
和NavigableText
对象。 以上面的文档为例:
lastPTag = soup('p')[-1]
lastPTag.findAllPrevious(text=True)
# [u'.', u'one', u'This is paragraph ', u'Page title']
# Note the reverse order!
lastPTag.findPrevious('p')
# <p id="firstpara" align="center">This is paragraph <b>one</b>.</p>
lastPTag.findPrevious('b')
# <b>one</b>
findParents(name, attrs, limit, **kwargs)
and findParent(name, attrs, **kwargs)
这两个方法以parent
成员为依据, 获得满足条件的Tag
和NavigableText
对象。 他们没有text
参数,因为这里的对象的parent不会有NavigableString
。 以上面的文档为例:
bTag = soup.find('b')
[tag.name for tag in bTag.findParents()]
# [u'p', u'body', u'html', '[document]']
# NOTE: "u'[document]'" means that that the parser object itself matched.
bTag.findParent('body').name
# u'body'