python BeautifulSoup库用法总结

 

1. Beautiful Soup 简介

简单来讲,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释以下:html

Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,经过解析文档为用户提供须要抓取的数据,由于简单,因此不须要多少代码就能够写出一个完整的应用程序。Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不须要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。而后,你仅仅须要说明一下原始编码方式就能够了。Beautiful Soup已成为和lxml、html6lib同样出色的python解释器,为用户灵活地提供不一样的解析策略或强劲的速度。html5

2. Beautiful Soup 安装

Beautiful Soup 3 目前已经中止开发,推荐在如今的项目中使用Beautiful Soup 4,不过它已经被移植到BS4了,也就是说导入时咱们须要 import bs4 。python

能够利用 pip 或者 easy_install 来安装,如下两种方法都可正则表达式

easy_install beautifulsoup4  
pip install beautifulsoup4  

若是想安装最新的版本,请直接下载安装包来手动安装,也是十分方便的方法。下载完成以后解压,运行下面的命令便可完成安装(先cd到解压后的目录)express

python setup.py install

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,若是咱们不安装它,则 Python 会使用 Python默认的解析器,lxml 解析器更增强大,速度更快,推荐安装.浏览器

 

解析器ide

使用方法函数

优点工具

劣势编码

Python标准库

BeautifulSoup(markup, “html.parser”)

Python的内置标准库

执行速度适中

文档容错能力强

Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差

lxml HTML 解析器

BeautifulSoup(markup, “lxml”)

速度快

文档容错能力强

须要安装C语言库

lxml XML 解析器

BeautifulSoup(markup, [“lxml”, “xml”])

BeautifulSoup(markup, “xml”)

速度快

惟一支持XML的解析器

须要安装C语言库

html5lib

BeautifulSoup(markup, “html5lib”)

最好的容错性

以浏览器的方式解析文档

生成HTML5格式的文档

速度慢

不依

安装lxml 和 html5lib:

1 easy_install lxml  
2 pip install lxml 
1 easy_install html5lib  
2 pip install html5lib  

3. 建立 Beautiful Soup 对象

首先导入 bs4 库,而后建立beautifulsoup对象

 1 from bs4 import BeautifulSoup 
 2 
 3 html = """  
 4 <html><head><title>The Dormouse's story</title></head>  
 5 <body>  
 6 <p class="title" name="dromouse"><b>The Dormouse's story</b></p>  
 7 <p class="story">Once upon a time there were three little sisters; and their names were  
 8 <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,  
 9 <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and  
10 <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;  
11 and they lived at the bottom of a well.</p>  
12 <p class="story">...</p>  
13 """  
14 
15 soup = BeautifulSoup(html)
16 soup = BeautifulSoup(open('index.html'))  #使用本地文件建立对象

打印一下 soup 对象的内容,格式化输出

1 print soup.prettify()

指定编码:当html为其余类型编码(非utf-8和ascii),好比GB2312的话,则须要指定相应的字符编码,BeautifulSoup才能正确解析。

htmlCharset = "GB2312"  
soup = BeautifulSoup(respHtml, fromEncoding=htmlChars
from bs4 import BeautifulSoup
import bs4
import re

# 待分析字符串
html_doc = """ 
<html> 
    <head> 
        <title>The Dormouse's story</title> 
    </head> 
    <body> 
    <p class="title aq"> 
        <b> 
            The Dormouse's story 
        </b> 
    </p> 

    <p class="story">Once upon a time there were three little sisters; and their names were 
        <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, 
        <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>  
        and 
        <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; 
        and they lived at the bottom of a well. 
    </p> 

    <p class="story">...</p> 
    </body>
</html>
"""
# 每一段代码中注释部分即为运行结果
# html字符串建立BeautifulSoup对象
soup = BeautifulSoup(html_doc, 'html.parser', from_encoding='utf-8')

# 输出第一个 title 标签
print(soup.title)
# <title>The Dormouse's story</title>

# 输出第一个 title 标签的标签名称
print(soup.title.name)
# title

# 输出第一个 title 标签的包含内容
print(soup.title.string)
# The Dormouse's story

# 输出第一个 title 标签的父标签的标签名称
print(soup.title.parent.name)
# head

# 输出第一个 p 标签
print(soup.p)
"""
<p class="title aq">
<b> 
            The Dormouse's story 
        </b>
</p>
"""
# 输出第一个 p 标签的 class 属性内容
print(soup.p['class'])
# ['title', 'aq']

# 输出第一个 a 标签的  href 属性内容
print(soup.a['href'])
# http://example.com/elsie

''''' 
soup的属性能够被添加,删除或修改. 操做方法与字典同样 
'''
# 修改第一个 a 标签的href属性为 http://www.baidu.com/
# soup.a['href'] = 'http://www.baidu.com/'

# 给第一个 a 标签添加 name 属性
# soup.a['name'] = u'百度'

# 删除第一个 a 标签的 class 属性为
# del soup.a['class']

##输出第一个 p 标签的全部子节点
print(soup.p.contents)
"""
['\n', <b> 
            The Dormouse's story 
        </b>, '\n']
"""

# 输出第一个 a 标签
print(soup.a)
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# 输出全部的 a 标签,以列表形式显示
print(soup.find_all('a'))
"""
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, 
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, 
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
"""

# 输出第一个 id 属性等于  link3 的  a 标签
print(soup.find(id="link3"))
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

# 获取全部文字内容
print(soup.get_text())
"""
The Dormouse's story
            The Dormouse's story 
Once upon a time there were three little sisters; and their names were 
        Elsie, 
        Lacie  
        and 
        Tillie; 
        and they lived at the bottom of a well. 
...
"""
# 输出第一个  a 标签的全部属性信息
print(soup.a.attrs)
# {'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}

for link in soup.find_all('a'):
    # 获取 link 的  href 属性内容
    print(link.get('href'))
"""
 http://example.com/elsie
 http://example.com/lacie
 http://example.com/tillie
"""
# 对soup.p的子节点进行循环输出
for child in soup.p.children:
    print("对soup.p的子节点进行循环输出", child)
"""
对soup.p的子节点进行循环输出 

对soup.p的子节点进行循环输出 <b> 
            The Dormouse's story 
        </b>
对soup.p的子节点进行循环输出 

"""
# 正则匹配,名字中带有b的标签
for tag in soup.find_all(re.compile(r"b")):
    print(tag.name)
"""
body
b
"""

 

4. 四大对象种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每一个节点都是Python对象,全部对象能够概括为4种:

  1. Tag  
  2. NavigableString  
  3. BeautifulSoup  
  4. Comment 

(1)Tag

Tag 是什么?通俗点讲就是 HTML 中的一个个标签,例如

<title>The Dormouse's story</title>  
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>  

上面的< title>< a> 等、 标签加上里面包括的内容就是 Tag,利用 soup加标签名轻松地获取这些标签的内容,是否是感受比正则表达式方便多了?不过有一点是,它查找的是在全部内容中的第一个符合要求的标签。soup.title 获得的是title标签,soup.p 获得的是文档中的第一个p标签,要想获得全部标签,得用find_all函数。find_all 函数返回的是一个序列,能够对它进行循环,依次获得想到的东西.。

咱们能够验证一下这些对象的类型

1 print type(soup.a)  
2 #<class 'bs4.element.Tag'> 

 

对于 Tag,它有两个重要的属性,是 name 和 attrs

name

1 print soup.name  
2 print soup.head.name  
3 #[document]  
4 #head  

soup 对象自己比较特殊,它的 name 即为 [document],对于其余内部标签,输出的值便为标签自己的名称。

attrs

1 print soup.p.attrs  
2 #{'class': ['title'], 'name': 'dromouse'}

 

在这里,咱们把 p 标签的全部属性打印输出了出来,获得的类型是一个字典。若是咱们想要单独获取某个属性,能够这样,例如咱们获取它的 class 叫什么

1 print soup.p['class']  
2 #['title']  

 

还能够这样,利用get方法,传入属性的名称,两者是等价的

print soup.p.get('class')  
#['title'] 

 

咱们能够对这些属性和内容等等进行修改,例如

1 soup.p['class']="newClass"  
2 print soup.p  
3 #<p class="newClass" name="dromouse"><b>The Dormouse's story</b></p> 

 

还能够对这个属性进行删除,例如

1 del soup.p['class']  
2 print soup.p  
3 #<p name="dromouse"><b>The Dormouse's story</b></p> 

 

不过,对于修改删除的操做,不是咱们的主要用途,在此不作详细介绍了,若是有须要,请查看前面提供的官方文档

 

1 head = soup.find('head')  
2 #head = soup.head  
3 #head = soup.contents[0].contents[0]  
4 print head  
5   
6 html = soup.contents[0]       # <html> ... </html>  
7 head = html.contents[0]       # <head> ... </head>  
8 body = html.contents[1]       # <body> ... </body>  

能够经过Tag.attrs访问,返回字典结构的属性。

或者Tag.name这样访问特定属性值,若是是多值属性则以列表形式返回。

 

(2)NavigableString

既然咱们已经获得了标签的内容,那么问题来了,咱们要想获取标签内部的文字怎么办呢?很简单,用 .string 便可,例如

 

1 print soup.p.string  
2 #The Dormouse's story 

这样咱们就轻松获取到了标签里面的内容,想一想若是用正则表达式要多麻烦。它的类型是一个 NavigableString,翻译过来叫 能够遍历的字符串,不过咱们最好仍是称它英文名字吧。来检查一下它的类型

1 print type(soup.p.string)  
2 #<class 'bs4.element.NavigableString'>

 

(3)BeautifulSoup

BeautifulSoup 对象表示的是一个文档的所有内容.大部分时候,能够把它看成 Tag 对象,是一个特殊的 Tag,咱们能够分别获取它的类型,名称,以及属性来感觉一下

 

1 print type(soup.name)  
2 #<type 'unicode'>  
3 print soup.name   
4 # [document]  
5 print soup.attrs   
6 #{} 空字典

 

(4)Comment

Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号,可是若是很差好处理它,可能会对咱们的文本处理形成意想不到的麻烦。

咱们找一个带注释的标签

1 print soup.a  
2 print soup.a.string  
3 print type(soup.a.string)  

运行结果以下:

1 <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>  
2  Elsie   
3 <class 'bs4.element.Comment'>

a 标签里的内容其实是注释,可是若是咱们利用 .string 来输出它的内容,咱们发现它已经把注释符号去掉了,因此这可能会给咱们带来没必要要的麻烦。

 另外咱们打印输出下它的类型,发现它是一个 Comment 类型,因此,咱们在使用前最好作一下判断,判断代码以下: 

1 if type(soup.a.string)==bs4.element.Comment:  
2     print soup.a.string  

上面的代码中,咱们首先判断了它的类型,是否为 Comment 类型,而后再进行其余操做,如打印输出。

 

5. 遍历文档树

(1)直接子节点

Tag.Tag_child1:直接经过下标名称访问子节点。

Tag.contents:以列表形式返回全部子节点。

Tag.children:生成器,可用于循环访问:for child in Tag.children

要点:.contents .children 属性

.contents

tag 的 .content 属性能够将tag的子节点以列表的方式输出。可使用 [num] 的形式得到。使用contents向后遍历树,使用parent向前遍历树: 

1 print soup.head.contents   
2 #[<title>The Dormouse's story</title>] 

输出方式为列表,咱们能够用列表索引来获取它的某一个元素

1 print soup.head.contents[0]  
2 #<title>The Dormouse's story</title> 

 

.children

它返回的不是一个 list,不过咱们能够经过遍历获取全部子节点。咱们打印输出 .children 看一下,能够发现它是一个 list 生成器对象。

可使用list能够将其转化为列表。固然可使用for 语句遍历里面的孩子。 

1 print soup.head.children  
2 #<listiterator object at 0x7f71457f5710> 

咱们怎样得到里面的内容呢?很简单,遍历一下就行了:

1 for child in  soup.body.children:  
2     print child  

结果以下:

 1 <p class="title" name="dromouse"><b>The Dormouse's story</b></p>  
 2   
 3 <p class="story">Once upon a time there were three little sisters; and their names were  
 4 <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,  
 5 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and  
 6 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;  
 7 and they lived at the bottom of a well.</p>  
 8   
 9   
10 <p class="story">...</p>  

 

(2)全部子孙节点

知识点:.descendants 属性

.descendants

.contents 和 .children 属性仅包含tag的直接子节点,.descendants 属性能够对全部tag的子孙节点进行递归循环,和 children相似,咱们也须要遍历获取其中的内容。

Tag.descendants:生成器,可用于循环访问:for des inTag.descendants 

1 for child in soup.descendants:  
2     print child  

 

运行结果以下,能够发现,全部的节点都被打印出来了,先生成最外层的 HTML标签,其次从 head 标签一个个剥离,以此类推。

 1 <html><head><title>The Dormouse's story</title></head>  
 2 <body>  
 3 <p class="title" name="dromouse"><b>The Dormouse's story</b></p>  
 4 <p class="story">Once upon a time there were three little sisters; and their names were  
 5 <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,  
 6 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and  
 7 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;  
 8 and they lived at the bottom of a well.</p>  
 9 <p class="story">...</p>  
10 </body></html>  
11 <head><title>The Dormouse's story</title></head>  
12 <title>The Dormouse's story</title>  
13 The Dormouse's story  
14   
15   
16 <body>  
17 <p class="title" name="dromouse"><b>The Dormouse's story</b></p>  
18 <p class="story">Once upon a time there were three little sisters; and their names were  
19 <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,  
20 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and  
21 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;  
22 and they lived at the bottom of a well.</p>  
23 <p class="story">...</p>  
24 </body>  
25   
26   
27 <p class="title" name="dromouse"><b>The Dormouse's story</b></p>  
28 <b>The Dormouse's story</b>  
29 The Dormouse's story  
30   
31   
32 <p class="story">Once upon a time there were three little sisters; and their names were  
33 <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,  
34 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and  
35 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;  
36 and they lived at the bottom of a well.</p>  
37 Once upon a time there were three little sisters; and their names were  
38   
39 <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>  
40  Elsie   
41 ,  
42   
43 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>  
44 Lacie  
45  and  
46   
47 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>  
48 Tillie  
49 ;  
50 and they lived at the bottom of a well.  
51   
52   
53 <p class="story">...</p>  
54 ...  
View Code

 

(3)节点内容

知识点:.string 属性

Tag.String:Tag只有一个String子节点时,能够这么访问,不然返回None
Tag.Strings:生成器,可用于循环访问:for str in Tag.Strings

若是tag只有一个 NavigableString 类型子节点,那么这个tag可使用 .string 获得子节点。若是一个tag仅有一个子节点,那么这个tag也可使用 .string 方法,输出结果与当前惟一子节点的 .string 结果相同。通俗点说就是:若是一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。若是标签里面只有惟一的一个标签了,那么 .string 也会返回最里面的内容。若是超过一个标签的话,那么就会返回None。例如 

1 print soup.head.string  
2 #The Dormouse's story  
3 print soup.title.string  
4 #The Dormouse's story  
View Code

若是tag包含了多个子节点,tag就没法肯定,string 方法应该调用哪一个子节点的内容, .string 的输出结果是 None

1 print soup.html.string  
2 # None 
View Code

 

(4)多个内容

知识点: .strings .stripped_strings 属性

.strings

获取多个内容,不过须要遍历获取,好比下面的例子 

 1 for string in soup.strings:  
 2     print(repr(string))  
 3     # u"The Dormouse's story"  
 4     # u'\n\n'  
 5     # u"The Dormouse's story"  
 6     # u'\n\n'  
 7     # u'Once upon a time there were three little sisters; and their names were\n'  
 8     # u'Elsie'  
 9     # u',\n'  
10     # u'Lacie'  
11     # u' and\n'  
12     # u'Tillie'  
13     # u';\nand they lived at the bottom of a well.'  
14     # u'\n\n'  
15     # u'...'  
16     # u'\n'  
View Code

.stripped_strings 

输出的字符串中可能包含了不少空格或空行,使用 .stripped_strings 能够去除多余空白内容: 

 1 for string in soup.stripped_strings:  
 2     print(repr(string))  
 3     # u"The Dormouse's story"  
 4     # u"The Dormouse's story"  
 5     # u'Once upon a time there were three little sisters; and their names were'  
 6     # u'Elsie'  
 7     # u','  
 8     # u'Lacie'  
 9     # u'and'  
10     # u'Tillie'  
11     # u';\nand they lived at the bottom of a well.'  
12     # u'...'  
View Code

 

(5)父节点

知识点: .parent 属性

使用parent获取父节点。

Tag.parent:父节点
Tag.parents:父到根的全部节点 

1 body = soup.body  
2 html = body.parent             # html是body的父亲  
View Code
1 p = soup.p  
2 print p.parent.name  
3 #body  
4   
5 content = soup.head.title.string  
6 print content.parent.name  
7 #title  
View Code

 

(6)所有父节点

知识点:.parents 属性

经过元素的 .parents 属性能够递归获得元素的全部父辈节点,例如: 

1 content = soup.head.title.string  
2 for parent in  content.parents:  
3     print parent.name  
4   
5 title  
6 head  
7 html  
8 [document]  
View Code

 

(7)兄弟节点

知识点:.next_sibling .previous_sibling 属性

使用nextSibling, previousSibling获取先后兄弟

Tag.next_sibling
Tag.next_siblings

Tag.previous_sibling
Tag.previous_siblings

兄弟节点能够理解为和本节点处在统一级的节点,.next_sibling 属性获取了该节点的下一个兄弟节点,.previous_sibling 则与之相反,若是节点不存在,则返回 None。

注意:实际文档中的tag的 .next_sibling 和 .previous_sibling 属性一般是字符串或空白,由于空白或者换行也能够被视做一个节点,因此获得的结果多是空白或者换行。 

 1 print soup.p.next_sibling  
 2 #       实际该处为空白  
 3 print soup.p.prev_sibling  
 4 #None   没有前一个兄弟节点,返回 None  
 5 print soup.p.next_sibling.next_sibling  
 6 #<p class="story">Once upon a time there were three little sisters; and their names were  
 7 #<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,  
 8 #<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and  
 9 #<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;  
10 #and they lived at the bottom of a well.</p>  
11 #下一个节点的下一个兄弟节点是咱们能够看到的节点  
View Code

 

.next方法:只能针对单一元素进行.next,或者说是对contents列表元素的挨个清点。

1 好比  
2 soup.contents[1]=u'HTML'  
3 soup.contents[2]=u'\n'  
4 则 soup.contents[1].next 等价于 soup.contents[2]  
5 
6 head = body.previousSibling    # head和body在同一层,是body的前一个兄弟  
7 p1 = body.contents[0]          # p1, p2都是body的儿子,咱们用contents[0]取得p1  
8 p2 = p1.nextSibling            # p2与p1在同一层,是p1的后一个兄弟, 固然body.content[1]也可获得  
View Code

contents[]的灵活运用也能够寻找关系节点,寻找祖先或者子孙能够采用findParent(s), findNextSibling(s), findPreviousSibling(s)

 

(8)所有兄弟节点

知识点:.next_siblings .previous_siblings 属性

经过 .next_siblings 和 .previous_siblings 属性能够对当前节点的兄弟节点迭代输出。 

1 for sibling in soup.a.next_siblings:  
2     print(repr(sibling))  
3     # u',\n'  
4     # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>  
5     # u' and\n'  
6     # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>  
7     # u'; and they lived at the bottom of a well.'  
8     # None  
View Code

 

(9)先后节点

知识点:.next_element .previous_element 属性

与 .next_sibling .previous_sibling 不一样,它并非针对于兄弟节点,而是在全部节点,不分层次。好比 head 节点为 

1 <head><title>The Dormouse's story</title></head>

那么它的下一个节点即是 title,它是不分层次关系的

1 print soup.head.next_element  
2 #<title>The Dormouse's story</title>  
View Code

 

(10)全部先后节点

知识点:.next_elements .previous_elements 属性

经过 .next_elements 和 .previous_elements 的迭代器就能够向前或向后访问文档的解析内容,就好像文档正在被解析同样。 

1 for element in last_a_tag.next_elements:  
2     print(repr(element))  
3 # u'Tillie'  
4 # u';\nand they lived at the bottom of a well.'  
5 # u'\n\n'  
6 # <p class="story">...</p>  
7 # u'...'  
8 # u'\n'  
9 # None  
View Code

 

6.搜索文档树

最经常使用的是find_all()函数

(1)find_all( name , attrs , recursive , text , **kwargs )

find_all() 方法搜索当前tag的全部tag子节点,并判断是否符合过滤器的条件

1)name 参数

name 参数能够查找全部名字为 name 的tag,字符串对象会被自动忽略掉。 

 1 #第一个参数为Tag的名称   
 2 tag.find_all(‘title’)    
 3 #获得”<title>&%^&*</title>”,结果为一个列表    
 4   
 5 第二个参数为匹配的属性  
 6 tag.find_all(“title”,class=”sister”)    
 7 #获得如”<title class = “sister”>%^*&</title>    
 8   
 9 # 第二个参数也能够为字符串,获得字符串匹配的结果  
10 tag.find_all(“title”,”sister”)    
11 #获得如”<title class = “sister”>%^*&</title>
View Code

A.传字符串

最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中全部的<b>标签

1 soup.find_all('b')  
2 # [<b>The Dormouse's story</b>]  
3   
4 print soup.find_all('a')  
5 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]  
View Code

 

B.传正则表达式

若是传入正则表达式做为参数,Beautiful Soup会经过正则表达式的 match() 来匹配内容.下面例子中找出全部以b开头的标签,这表示<body>和<b>标签都应该被找到

1 import re  
2 for tag in soup.find_all(re.compile("^b")):  
3     print(tag.name)  
4 # body  
5 # b  
View Code

 

C.传列表

若是传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中全部<a>标签和<b>标签

1 soup.find_all(["a", "b"])  
2 # [<b>The Dormouse's story</b>,  
3 #  <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,  
4 #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,  
5 #  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]  
View Code

 

D.传 True

True 能够匹配任何值,下面代码查找到全部的tag,可是不会返回字符串节点

 1 for tag in soup.find_all(True):  
 2     print(tag.name)  
 3 # html  
 4 # head  
 5 # title  
 6 # body  
 7 # p  
 8 # b  
 9 # p  
10 # a  
11 # a  
View Code

 

E.传方法

若是没有合适过滤器,那么还能够定义一个方法,方法只接受一个元素参数 [4] ,若是这个方法返回 True 表示当前元素匹配而且被找到,若是不是则反回 False。下面方法校验了当前元素,若是包含 class 属性却不包含 id 属性,那么将返回 True:

1 def has_class_but_no_id(tag):  
2     return tag.has_attr('class') and not tag.has_attr('id')
View Code

将这个方法做为参数传入 find_all() 方法,将获得全部<p>标签:

1 soup.find_all(has_class_but_no_id)  
2 # [<p class="title"><b>The Dormouse's story</b></p>,  
3 #  <p class="story">Once upon a time there were...</p>,  
4 #  <p class="story">...</p>]  
View Code

 

2)keyword 参数

注意:若是一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数看成指定名字tag的属性来搜索,若是包含一个名字为 id 的参数,Beautiful Soup会搜索每一个tag的”id”属性 

1 soup.find_all(id='link2')  
2 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]  
View Code

若是传入 href 参数,Beautiful Soup会搜索每一个tag的”href”属性

1 soup.find_all(href=re.compile("elsie"))  
2 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]  
View Code

使用多个指定名字的参数能够同时过滤tag的多个属性

1 soup.find_all(href=re.compile("elsie"), id='link1')  
2 # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>]  
View Code

在这里咱们想用 class 过滤,不过 class 是 python 的关键词,这怎么办?加个下划线就能够。

1 soup.find_all("a", class_="sister")  
2 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,  
3 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,  
4 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]  
View Code

有些tag属性在搜索不能使用,好比HTML5中的 data-* 属性。 

1 data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')  
2 data_soup.find_all(data-foo="value")  
3 # SyntaxError: keyword can't be an expression  
View Code

可是能够经过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag

1 data_soup.find_all(attrs={"data-foo": "value"})  
2 # [<div data-foo="value">foo!</div>]  
View Code

 

3)text 参数 

经过 text 参数能够搜搜文档中的字符串内容.与 name 参数的可选值同样, text 参数接受 字符串 , 正则表达式 , 列表, True。 

1 soup.find_all(text="Elsie")  
2 # [u'Elsie']  
3   
4 soup.find_all(text=["Tillie", "Elsie", "Lacie"])  
5 # [u'Elsie', u'Lacie', u'Tillie']  
6   
7 soup.find_all(text=re.compile("Dormouse"))  
8 [u"The Dormouse's story", u"The Dormouse's story"]  
View Code

 

4)limit 参数 

find_all() 方法返回所有的搜索结构,若是文档树很大那么搜索会很慢.若是咱们不须要所有结果,可使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字相似,当搜索到的结果数量达到 limit 的限制时,就中止搜索返回结果.

文档树中有3个tag符合搜索条件,但结果只返回了2个,由于咱们限制了返回数量

1 soup.find_all("a", limit=2)  
2 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,  
3 #  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] 
View Code

 

5)recursive 参数

 调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的全部子孙节点,若是只想搜索tag的直接子节点,可使用参数 recursive=False 。一段简单的文档: 

1 <html>  
2  <head>  
3   <title>  
4    The Dormouse's story  
5   </title>  
6  </head>  
7 ...  
View Code

是否使用 recursive 参数的搜索结果: 

1 soup.html.find_all("title")  
2 # [<title>The Dormouse's story</title>]  
3   
4 soup.html.find_all("title", recursive=False)  
5 # []  
View Code

 

(2)find(name=None, attrs={}, recursive=True, text=None, **kwargs)

 它与 find_all() 方法惟一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果。

.find('p'),.findAll('p'):find返回的是字符串值,并且是返回从头查找到的第一个tag对。可是若是这第一个tag对包括大量的内容,父等级很高,则同时其内部所包含的,此级标签也所有都find。findAll返回值是个列表,若是发现了一个同名标签内含多个同名标签,则内部的标签一并归于该父标签显示,列表其余元素也再也不体现那些内含的同名子标签。即findAll会返回全部符合要求的结果,并以list返回。

 1 soup.findAll(onclick='document.location...')  
 2     soup.findAll(attrs={'style':r'outline:none;'}) #用来查找属性中有style='outline:none;的标签体。                                 # 搜索全部tag  
 3 
 4 tag搜索  
 5 find(tagname)                                  # 直接搜索名为tagname的tag 如:find('head')  
 6 find(list)                                     # 搜索在list中的tag,如: find(['head', 'body'])  
 7 find(dict)                                     # 搜索在dict中的tag,如:find({'head':True, 'body':True})  
 8 find(re.compile(''))                           # 搜索符合正则的tag, 如:find(re.compile('^p')) 搜索以p开头的tag  
 9 find(lambda)                       # 搜索函数返回结果为true的tag, 如:find(lambda name: if len(name) == 1) 搜索长度为1的tag  
10 find(True)                                     # 搜索全部tag  
11   
12 attrs搜索  
13 find(id='xxx')                                  # 寻找id属性为xxx的  
14 find(attrs={id=re.compile('xxx'), algin='xxx'}) # 寻找id属性符合正则且algin属性为xxx的  
15 find(attrs={id=True, algin=None})               # 寻找有id属性可是没有algin属性的  
16   
17 resp1 = soup.findAll('a', attrs = {'href': match1})  
18 resp2 = soup.findAll('h1', attrs = {'class': match2})  
19 resp3 = soup.findAll('img', attrs = {'id': match3})  
20   
21 text搜索  
22    文字的搜索会致使其余搜索给的值如:tag, attrs都失效。方法与搜索tag一致     
23 print p1.text  
24 # u'This is paragraphone.'  
25 print p2.text  
26 # u'This is paragraphtwo.'  
27 # 注意:1,每一个tag的text包括了它以及它子孙的text。2,全部text已经被自动转为unicode,若是须要,能够自行转码encode(xxx)  
28   
29 recursive和limit属性  
30 recursive=False表示只搜索直接儿子,不然搜索整个子树,默认为True。  
31 当使用findAll或者相似返回list的方法时,limit属性用于限制返回的数量,  
32 如:findAll('p', limit=2): 返回首先找到的两个tag  
View Code

 

(3)find_parents()  find_parent()

find_all() 和 find() 只搜索当前节点的全部子节点,孙子节点等. find_parents() 和 find_parent() 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档搜索文档包含的内容

(4)find_next_siblings()  find_next_sibling()

这2个方法经过 .next_siblings 属性对当 tag 的全部后面解析的兄弟 tag 节点进行迭代, find_next_siblings() 方法返回全部符合条件的后面的兄弟节点,find_next_sibling() 只返回符合条件的后面的第一个tag节点

(5)find_previous_siblings()  find_previous_sibling()

这2个方法经过 .previous_siblings 属性对当前 tag 的前面解析的兄弟 tag 节点进行迭代, find_previous_siblings()方法返回全部符合条件的前面的兄弟节点, find_previous_sibling() 方法返回第一个符合条件的前面的兄弟节点

(6)find_all_next()  find_next()

这2个方法经过 .next_elements 属性对当前 tag 的以后的 tag 和字符串进行迭代, find_all_next() 方法返回全部符合条件的节点, find_next() 方法返回第一个符合条件的节点

(7)find_all_previous() 和 find_previous()

这2个方法经过 .previous_elements 属性对当前节点前面的 tag 和字符串进行迭代, find_all_previous() 方法返回全部符合条件的节点, find_previous()方法返回第一个符合条件的节点

注:以上(2)(3)(4)(5)(6)(7)方法参数用法与 find_all() 彻底相同,原理均相似,在此再也不赘述。

7. CSS选择器

在写 CSS 时,标签名不加任何修饰,类名前加点,id名前加 #

在这里咱们也能够利用相似的方法来筛选元素,用到的方法是 soup.select(),返回类型是 list

(1)经过标签名查找 

1 print soup.select('title')   
2 #[<title>The Dormouse's story</title>] 
3 
4 print soup.select('a')  
5 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]  
6 
7 print soup.select('b')  
8 #[<b>The Dormouse's story</b>]
View Code

 

(2)经过类名查找

1 print soup.select('.sister')  
2 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]  
View Code

 

(3)经过 id 名查找

1 print soup.select('#link1')  
2 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]  
View Code

 

(4)组合查找

组合查找即和写 class 文件时,标签名与类名、id名进行的组合原理是同样的,例如:查找 p 标签中,id 等于 link1的内容,两者须要用空格分开

1 print soup.select('p #link1')  
2 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>] 

直接子标签查找

1 print soup.select("head > title")  
2 #[<title>The Dormouse's story</title>]  

 

(5)属性查找

查找时还能够加入属性元素,属性须要用中括号括起来,注意属性和标签属于同一节点,因此中间不能加空格,不然会没法匹配到。

1 print soup.select('a[class="sister"]')  
2 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]  
3 
4 print soup.select('a[href="http://example.com/elsie"]')  
5 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>] 
View Code

一样,属性仍然能够与上述查找方式组合,不在同一节点的空格隔开,同一节点的不加空格。

1 print soup.select('p a[href="http://example.com/elsie"]')  
2 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]  
View Code

以上的 select 方法返回的结果都是列表形式,能够遍历形式输出,而后用 get_text() 方法来获取它的内容。

1 soup = BeautifulSoup(html, 'lxml')  
2 print type(soup.select('title'))  
3 print soup.select('title')[0].get_text()  
4   
5 for title in soup.select('title'):  
6     print title.get_text()  
View Code

这就是另外一种与 find_all 方法有殊途同归之妙的查找方法,是否是感受很方便?

 1 print soup.find_all("a", class_="sister")  
 2 print soup.select("p.title")  
 3   
 4 # 经过属性进行查找  
 5 print soup.find_all("a", attrs={"class": "sister"})  
 6   
 7 # 经过文本进行查找  
 8 print soup.find_all(text="Elsie")  
 9 print soup.find_all(text=["Tillie", "Elsie", "Lacie"])  
10   
11 # 限制结果个数  
12 print soup.find_all("a", limit=2)  
View Code
相关文章
相关标签/搜索