搜索剖析树
Beautiful Soup提供了许多方法用于浏览一个剖析树,收集你指定的
Tag
和
NavigableString
。
有几种方法去定义用于Beautiful Soup的匹配项。我们先用深入解释最基本的一种搜索方法
findAll
。和前面一样,我们使用下面这个文档说明:
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>
还有, 这里的两个方法(
findAll
和
find
)仅对
Tag
对象以及顶层剖析对象有效,但
NavigableString
不可用。这两个方法在
Searching 剖析树内部同样可用。
方法
findAll
从给定的点开始遍历整个树,并找到满足给定条件所有
Tag
以及
NavigableString
。
findall
函数原型定义如下:
findAll(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)
这些
参数会反复的在这个文档中出现。其中最重要的是
name
参数和keywords参数(译注:就是**kwargs参数)。
- 参数
name
匹配tags的名字,获得相应的结果集。有几种方法去匹配name,在这个文档中会一再的用到。
- 最简单用法是仅仅给定一个tag name值。下面的代码寻找文档中所有的 <B>
Tag
:
soup.findAll('b')#[<b>one</b>, <b>two</b>]
- 你可以传一个正则表达式。下面的代码寻找所有以b开头的标签:
import re
tagsStartingWithB = soup.findAll(re.compile('^b'))
[tag.name for tag in tagsStartingWithB]#[u'body', u'b', u'b']
- 你可以传一个list或dictionary。下面两个调用是查找所有的<TITLE>和<P>标签。他们获得结果一样,但是后一种方法更快一些:
soup.findAll(['title', 'p'])#[<title>Page title</title>,#<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,#<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
soup.findAll({'title' : True, 'p' : True})#[<title>Page title</title>,#<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,#<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
- 你可以传一个
True
值,这样可以匹配每个tag的name:也就是匹配每个tag。
allTags = soup.findAll(True)
[tag.name for tag in allTags]
[u'html', u'head', u'title', u'body', u'p', u'b', u'p', u'b']
这看起来不是很有用,但是当你限定属性(attribute)值时候,使用True
就很有用了。
- 你可以传callable对象,就是一个使用
Tag
对象作为它唯一的参数,并返回布尔值的对象。 findAll
使用的每个作为参数的Tag
对象都会传递给这个callable对象,并且如果调用返回True
,则这个tag便是匹配的。
下面是查找两个并仅两个属性的标签(tags):
soup.findAll(lambda tag: len(tag.attrs) == 2)#[<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,#<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
下面是寻找单个字符为标签名并且没有属性的标签:
soup.findAll(lambda tag: len(tag.name) == 1 and not tag.attrs)#[<b>one</b>, <b>two</b>]
keyword参数用于筛选tag的属性。下面这个例子是查找拥有属性align且值为center的所有标签:
soup.findAll(align="center")#[<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>]
如同name
参数,你也可以使用不同的keyword参数对象,从而更加灵活的指定属性值的匹配条件。你可以向上面那样传递一个字符串,来匹配属性的值。你也可以传递一个正则表达式,一个列表(list),一个哈希表(hash),特殊值True
或None
,或者一个可调用的以属性值为参数的对象(注意:这个值可能为None
)。
一些例子:
- soup.findAll(id=re.compile("para$"))#[<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,#<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
- soup.findAll(align=["center", "blah"])#[<p id="firstpara" align="center">This is paragraph <b>one</b>.</p>,#<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]
- soup.findAll(align=lambda(value): value and len(value) < 5)#[<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]