Beautiful Soup 中文文档之五

搜索剖析树

Beautiful Soup提供了许多方法用于浏览一个剖析树,收集你指定的TagNavigableString有几种方法去定义用于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>
还有, 这里的两个方法(findAllfind)仅对Tag对象以及顶层剖析对象有效,但 NavigableString不可用。这两个方法在Searching 剖析树内部同样可用。

The basic find method: findAll(name, attrs, recursive, text, limit, **kwargs)

方法findAll 从给定的点开始遍历整个树,并找到满足给定条件所有Tag以及NavigableStringfindall函数原型定义如下: findAll(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs) 这些参数会反复的在这个文档中出现。其中最重要的是name参数和keywords参数(译注:就是**kwargs参数)。
  • 参数name 匹配tags的名字,获得相应的结果集。有几种方法去匹配name,在这个文档中会一再的用到。
    1. 最简单用法是仅仅给定一个tag name值。下面的代码寻找文档中所有的 <B> Tag:
      soup.findAll('b')#[<b>one</b>, <b>two</b>]
    2. 你可以传一个正则表达式。下面的代码寻找所有以b开头的标签:
      import re
      tagsStartingWithB = soup.findAll(re.compile('^b'))
      [tag.name for tag in tagsStartingWithB]#[u'body', u'b', u'b']
    3. 你可以传一个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>]
    4. 你可以传一个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就很有用了。
    5. 你可以传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),特殊值TrueNone,或者一个可调用的以属性值为参数的对象(注意:这个值可能为None)。
    一些例子:
  1. 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>]
  2. 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>]
  3. soup.findAll(align=lambda(value): value and len(value) < 5)#[<p id="secondpara" align="blah">This is paragraph <b>two</b>.</p>]