欢迎来到Cecilia陈的博客

孤独,是人一生最好的修行。

06 解析库Beautiful Soup

一、Beautiful Soup介绍

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4

#安装 Beautiful Soup
pip install beautifulsoup4

#安装解析器
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:

$ apt-get install Python-lxml

$ easy_install lxml

$ pip install lxml

另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:

$ apt-get install Python-html5lib

$ easy_install html5lib

$ pip install html5lib

下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.

解析器 使用方法 优势 劣势
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格式的文档 速度慢不依赖外部扩展

中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

二、基本使用

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><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>
"""

#基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
res=soup.prettify() #处理好缩进,结构化显示
print(res)

三、遍历文档树

#遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
1、用法
2、获取标签的名称
3、获取标签的属性
4、获取标签的内容
5、嵌套选择
6、子节点、子孙节点
7、父节点、祖先节点
8、兄弟节点
# 示例
from bs4 import BeautifulSoup


'''基本参数
    markup='' 传入解析文本
    BeautifulSoup('解析文本内容','解析器')
    html.parser :python自带的写解析
    lxml:pip3 install lxml 第三方的解析库
'''

'''基础使用'''
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""
soup = BeautifulSoup(html_doc,'html.parser')
# print(soup) # 就是html内容,会自动将标签补全
# print(type(soup))
# print(soup.prettify()) # 将html文本美化 了解


'''基本用法
   遍历文档树,即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
'''
'''1.直接.标签名'''
print('1.直接.标签名'+'*'*100)
print(soup.head)
print(soup.a)

'''2.获取标签的名称 了解'''
print('2.获取标签的名称 了解'+'*'*100)
print(soup.p.name)


'''3、获取标签的属性 (*********)'''
print('3、获取标签的属性'+'*'*100)
print(soup.a.attrs) # 只返回第一个a标签的所有属性
print(type(soup.a.attrs)) # 返回的是一个字典
print(soup.a.attrs.get('id')) # 获取a标签中id属性值
print(soup.a.attrs.get('href')) # 获取a标签中href属性值


'''4、获取标签的文本内容'''
print('4、获取标签的文本内容'+'*'*100)
print(soup.a.text)# 获取第一个a标签中的文本内容


'''5.嵌套选择'''
print('5.嵌套选择'+'*'*100)
print(type(soup.html)) # 就是Beaytifulsoup类的对象
print(type(soup.html.head.title))
print(soup.html.head.title) # 选择soup.html中head下面的title


'''6、子节点、子孙节点'''
print('6、子节点、子孙节点'+'*'*100)
print(soup)  #注意: 换行符也算一个 节点
print(soup.body.contents)  # body下所有子节点,返回的是列表
print(len(soup.body.contents))  # body下所有子节点

'''优先使用children'''
print('优先使用children'+'*'*100)
print(soup.body.children)  # 得到一个迭代器,包含p下所有子节点
print(list(soup.body.children))  # 得到一个迭代器,包含p下所有子节点


'''7、父节点、祖先节点'''
print('7、父节点、祖先节点'+'*'*100)
print(soup.a.parent)  # 仅仅获取a标签的父节点
print(soup.a.parents)  # 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...,返回的是一个生成器
print(list(soup.a.parents))  # 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...


'''8、兄弟节点'''
print('8、兄弟节点'+'*'*100)
print(soup.a.next_sibling)  # 下一个兄弟,'\n'也算一个标签,也算是a标签的一个兄弟
print(soup.a.previous_sibling)  # 上一个兄弟,a标签的父级中有文本属性,所以也算是一级''

print(soup.a.next_siblings)  # 下面的兄弟们=>生成器对象
print(list(soup.a.next_siblings))
print(soup.a.previous_siblings) # 上面的兄弟们=>生成器对象
print(list(soup.a.previous_siblings)) 

四、搜索文档树

1. 五种过滤器

标签查找与属性查找:
    - 根据标签查找属性:
      查找第一个标签soup.find(name 属性匹配attrs 属性查找匹配text 文本匹配)
    	- 查找第一个a标签soup.find(name='a',attrs={'class': '属性值'})
	  查找所有标签
        - soup.find_all()

    标签:
        - 字符串过滤器   字符串全局匹配
            - name = 'p'
            name 属性匹配
            attrs 属性查找匹配
            text 文本匹配

        - 正则过滤器 re模块匹配
            - name = re.compile()
            name 属性匹配
            attrs 属性查找匹配
            text 文本匹配

        - 列表过滤器 列表内的数据匹配
            - name = ['tank', 100]
            name 属性匹配
            attrs 属性查找匹配
            text 文本匹配

        - bool过滤器 rue匹配
            - name = True
            name 属性匹配
            attrs 属性查找匹配
            text 文本匹配

        - 方法过滤器 于一些要的属性以及不需要的属性查找。
            - name = func()
            name 属性匹配
            attrs 属性查找匹配
            text 文本匹配

    属性:
        - class_
        - id

1.字符串:即标签名

from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""

soup = BeautifulSoup(html_doc, 'lxml')

'''1.字符串过滤器'''
print('*'*100,'(1).根据name查找节点标签')
a_tag = soup.find(name='a') # 只查第一个
print(a_tag)


print('*'*100,'(2).根据attrs属性查找节点标签')
a_tag = soup.find(attrs={"id": "tank"})
print(a_tag)

print('*'*100,'(3).根据文本找节点')
a_tag = soup.find(text='啊') # 根据文本查找的时候,文本必须要一摸一样才可以匹配成功
print(a_tag)


print('*'*100,'(4).name与attrs配合使用')
# attrs是以字典的形式用
res = soup.find(name='a', attrs={'id': 'link3'}, text='Tillie')
print(res)

2. re正则过滤器

'''2.正则过滤器
    re模块匹配
    - name = re.compile()
    name 属性匹配
    attrs 属性查找匹配
    text 文本匹配
'''
import re
from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""

soup = BeautifulSoup(html_doc, 'lxml')
print('*'*100,'2.正则过滤器--查找标签名字中包含a的节点')
res = soup.find(name=re.compile('a'))# 查找标签名字中包含a的节点
print(res)

3. 列表过滤器

'''3.列表过滤器
    列表内的数据匹配
    - name = ['tank', 100]
    name 属性匹配
    attrs 属性查找匹配
    text 文本匹配
'''
from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""
soup = BeautifulSoup(html_doc, 'lxml')
print('*'*100,'3.列表过滤器--获取第一个a标签 或 者p标签的节点')
res = soup.find(name=['a', 'p'])# 获取第一个a标签 或 者p标签的节点
print(res)
print('*'*100,'3.列表过滤器--获取所有的a标签与p标签的节点')
res = soup.find_all(name=['a', 'p'])# 获取所有的a标签与p标签的节点
print(res)

4.布尔过滤器

'''4.bool过滤器 (了解)
    True匹配
    name 属性匹配
    attrs 属性查找匹配
    text 文本匹配
'''
from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""
soup = BeautifulSoup(html_doc, 'lxml')
print('*'*100,'4.bool过滤器 (了解)--获取第一个a标签 或 者p标签的节点')
print(soup.find_all(True))
for tag in soup.find_all(True):
    print(tag.name)

5.方法过滤器

'''5.方法过滤器
    用于一些要的属性以及不需要的属性查找。
    - name = func()
    name 属性匹配
    attrs 属性查找匹配
    text 文本匹配
'''
from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""
soup = BeautifulSoup(html_doc, 'lxml')
print('*'*100,'5.方法过滤器--判断节点中有class没有id的节点,并将该节点返回')
# 函数用于判断节点中有class没有id的节点,并将该节点返回
def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')
print(soup.find_all(has_class_but_no_id))

2. CSS选择器

from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a id="tank" href="http://example.com/tank">今天是个好日子,祝大家越来越美丽</a>
<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>
"""

soup = BeautifulSoup(html_doc, 'lxml')

# CSS选择器
res = soup.select('#tank') # 选择id属性为tank
# print(res)
res1 = soup.select('.story')# 选择class属性为story包括他的儿子,返回列表
# print(res1)


res2 = soup.select('.story')[0].select('#tank') # 选择class属性为story下的id为tank的
print(res2)
# 可以用多个select,但其实一个select就可以解决
res3 = soup.select('.story #tank') # 选择class属性为story下的id为tank的
print(res3)

# 获取属性
res4 = soup.select('.story #tank')[0].attrs # 返回字典
print(res4)

# 获取文本
res5 = soup.select('.story #tank')[0].get_text()
print(res5)

五、修改文档树

https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id40

六、总结

# 总结:
#1、推荐使用lxml解析库
#2、讲了三种选择器:标签选择器,find与find_all,css选择器
    1、标签选择器筛选功能弱,但是速度快
    2、建议使用find,find_all查询匹配单个结果或者多个结果
    3、如果对css选择器非常熟悉建议使用select
#3、记住常用的获取属性attrs和文本值get_text()的方法
posted @ 2020-01-05 19:10  Cecilia陈  阅读(84)  评论(0编辑  收藏  举报