1. 安装方法
这里只介绍windows平台安装BeautifulSoup包的方法,主要有两种:
方法1. 直接在cmd窗口输入
pip install beautifulsoup4
方法2. 下载BS4的源码,通过setup.py来安装。setup.py的安装是在对应文件路径下打开cmd窗口,然后输入指令
python setup.py install
2. 使用方法
具体可查看官方文档,这里做一些简要介绍。
2.1 浏览器解析器
lxml 解析器更加强大,速度更快,推荐安装和使用。
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, “html.parser”) | 1.Python的内置标准库 2.执行速度适中 3. 文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, “lxml”) | 1.执行速度适中 2.文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, [“lxml”, “xml”])BeautifulSoup(markup, “xml”) | 1.速度快 2.唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, “html5lib”) | 1.最好的容错性 以浏览器的方式解析文档 生成HTML5格式的文档 | 速度慢 不依赖外部扩展 |
2.2 创建 Beautiful Soup 对象
先创建一个字符串,用于后面的文本处理
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
那么创建BeautifulSoup对象的方法如下
from bs4 import BeautifulSoup # 首先必须先导入bs4库
soup = BeautifulSoup(html, 'lxml') # 创建BeautifulSoup对象
也可以打开本地的HTML文件来创建对象,例如
soup = BeautifulSoup(open('demo.html'))
其中demo.html是本地文件
2.3 四大对象种类
HTML文档被BeautifulSoup转化为一个树状结构,每个节点都是Python对象。这些对象可以归纳为4类:
- Tag
- NavigableString
- BeautifulSoup
- Comment
(1) Tag
如果你了解html基础知识的话,就知道Tag是标签。
<title>The Dormous's story</title>
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
这里的title、a等就是Tag。那么BeautifulSoup是如何处理Tag的呢?
print(soup.title)
#<title>The Dormouse's story</title>
print soup.head
#<head><title>The Dormouse's story</title></head>
print soup.a
#<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
print soup.p
#<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
Tag有两个重要的属性,name和attrs。
name
print(soup.name)
print(soup.head.name)
#[document]
#head
attrs
print(soup.p.attrs)
#{'class': ['title'], 'name': 'dromouse'}
主要返回结果是一个dic型数据,而且只获得第一个符合要求的Tag。
如果想单独获取某个属性,比如说class属性,可以这么写
print(soup.p['class'])
#['title']
也可以用get方法
print(soup.p.get('class'))
#['title']
(2) NavigableString
NavigableString即可遍历的字符串。Tag内的文本信息可通过.string获取,返回的结果就是NavigableString类型的数据。
print(soup.p.string)
#The Dormouse's story
print(type(soup.p.string))
#<class 'bs4.element.NavigableString'>
(3) BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作一个特殊的 Tag。
print type(soup.name)
#<type 'unicode'>
print soup.name
# [document]
print soup.attrs
#{} 空字典
(4) Comment
Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。
print(soup.a)
print(soup.a.string)
print(type(soup.a.string))
运行结果如下
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
Elsie
<class 'bs4.element.Comment'>
a 标签里的内容实际上是注释,但是如果我们利用 .string 来输出它的内容,我们发现它已经把注释符号去掉了。
2.4 搜索文档树
(1)find_all(name, attrs, recursive, text, **kwargs)
find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
<name参数>
name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉。下面是name可以传入的参数类型。
传字符串
这个最简单,如要查找文档中所有的<a>的Tag
soup.find_all('a')
- 传正则表达式
如果传入正则表达式为参数,BeautifulSoup会通过正则表达式的match()来匹配内容。
import re
for tag in soup.find_all(re.compile('^b')):
print(tag.name)
- 传列表
如果传入列表参数,BeautifulSoup会将与列表中任一元素匹配的内容返回。
soup.find_all(['a', 'b'])
上面代码运行后会将文档中所有<a>标签和<b>标签筛选出来。
- 传True
True可以匹配任何值。
for tag in soup.find_all(True):
print(tag.name)
- 传方法
如果没有合适过滤器,还可定义一个方法。方法只接受一个元素参数,如果这个方法返回 True,则表示当前元素匹配并且被找到。
def class_noid(tag):
return tag.has_attr('class') and not tag.has_attr('id')
for tag in soup.find_all(class_noid):
print(tag)
<keyword参数>
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索。
soup.find_all(id='link2')
soup.find_all(href=re.compile('elsie'))
soup.find_all(href=re.compile('elsie'), id='link1') # 可以设置多个关键字参数进行过滤
注意,如果想用class做关键字参数,需要加个下划线(因为class是python的关键词)
soup.find_all('a', class_='sister')
有些tag属性无法用于搜索,如下
soup1 = BeautifulSoup('<div data-foo="value">foo!</div>')
soup1.find_all(data-foo="value")
这个时候可以通过fiand_all()的attrs参数定义一个字典参数,来搜索包含特殊属性的tag
soup1.find_all(attrs={'data-foo': 'value'})
<text参数>
通过 text 参数可以搜搜文档中的字符串内容。与 name 参数的可选值一样, text 参数接受 字符串 ,正则表达式 , 列表,True。
soup.find_all(text='Elsie')
soup.find_all(text=['Tillie', 'Elsie', 'Lacie'])
soup.find_all(text=re.compile('Dormouse'))
<limit参数>
limit参数是用于限制返回结果数目的参数,一般用于搜索文档大,返回结果多的情况。
soup.find_all('a', limit=2)
<recursive参数>
调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False。
html = '''
<html>
<head>
<title>
The Dormouse's story
</title>
</head>
'''
soup.html.find_all("title")
# [<title>The Dormouse's story</title>]
soup.html.find_all("title", recursive=False)
# []
注:以下(2)(3)(4)(5)(6)(7)方法参数用法与 find_all() 完全相同,原理均类似,在此不再赘述。
(2)find(name, attrs, recursive, text, **kwargs)
find()直接返回结果,而find_all()返回列表。其他无区别。
(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.5 CSS选择器
写CSS时,Tag不加任何修饰,class前加点,id前加#。这里利用这个特性来筛选元素,用到的方法是soup.select(),返回list数据类型。
(1)利用Tag查找
print(soup.select('title'))
print(soup.select('p'))
(2)利用class查找
print(soup.select('.sister'))
(3)利用id查找
print(soup.select('#link1'))
(4)组合查找
组合查找时,注意tag、class和id之间用空格分开
print(soup.select('p #link1'))
(5)属性查找
查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。
print(soup.select('a[class="sister"]'))
print(soup.select('a[href="http://example.com/elsie"]'))
同样,属性仍然可以与上述查找方式组合,不在同一节点的空格隔开,同一节点的不加空格。
print(soup.select('p a[href="http://example.com/elsie"]'))
以上的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。
soup = BeautifulSoup(html, 'lxml')
print(type(soup.select('title')))
print(soup.select('title')[0].get_text())
for title in soup.select('title'):
print(title.get_text())