前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文入门BeautifulSoup

一文入门BeautifulSoup

作者头像
皮大大
发布2021-03-01 16:05:43
3.9K0
发布2021-03-01 16:05:43
举报
文章被收录于专栏:机器学习/数据可视化

本文中主要介绍的BeautifulSoup4,从简介、安装、解析器使用、语法介绍、遍历文档树、搜索文档树等进行了介绍,能够快速地入门。

崔庆才-爬虫利器二之BS的用法

BS4-中文

什么是BS4

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式

安装bs4

代码语言:javascript
复制
pip  install beautifulsoup4

解析器

安装解析器

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

代码语言:javascript
复制
$ apt-get install Python-lxml
$ easy_install lxml
$ pip install lxml

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

代码语言:javascript
复制
$ apt-get install Python-html5lib
$ easy_install html5lib
$ pip install html5lib
常用解析器比较

下表列出了主要的解析器,以及它们的优缺点:

解析器

使用方法

优势

劣势

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格式的文档

速度慢

语法

官方解释

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

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

提取步骤

使用Beautiful Soup4提取HTML内容,一般要经过以下两步:

  • 处理源代码生成BeautifulSoup对象
  • 使用find_all()或者find()来查找内容
快速入门

使用的是\color{red}{爱丽丝梦游仙境}中的一段内容

代码语言:javascript
复制
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>
"""

下面?的内容是对官网中一些案例的提炼,也是经常会使用到的方法。

导入模块

使用之前先导入模块并且指定解析器,创建beautifulsoup对象的时候指定两个参数:

代码语言:javascript
复制
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'html.parser')  # 1-待解析文档;2-解析器指定

如果文件是在本地,使用open方法先打开再进行解析

代码语言:javascript
复制
soup = BeautifulSoup(open('index.html'), 'html.parser')
直接输出
缩进格式化输出-prettify()

能够按照标准的缩进格式进行输出!!!

需要记住该方法,方便查阅内容

浏览结构化数据-标签
  1. 使用soup加上标签能够轻松获取标签相关的内容,比正则更加方便了些。
  • 整个标签
  • 标签名称
  • 标签内容
  1. 如果存在多个相同的标签名,只会取到第一个

如果想查询所有的标签,往下看

  1. 查看相关的属性

四大对象种类

BS将HTML文档解析成一个复杂的树形结构,每个节点都可以看做是Python对象,所有对象可以归纳为4种:

  • Tag
  • NavigableString
  • BeautifulSoup
  • Comment
Tag(标签)

就是HTML中每个标签,下面就是一个完整的title、p标签

代码语言:javascript
复制
<title>The Dormouse's story</title>

<p class="title"><b>The Dormouse's story</b></p>

Tag对象与XML或者HTML原生文档中的tag相同

Tag对象的两个重要属性:name和attributes

name
  1. 每个tag都有自己的name。如果改变tag的name属性,那么将改变当前通过BS对象生成的HTML文档

\color{red}{注意}:soup 对象本身的name值是[document],对于内部其他标签,输出的值便是标签本身的名称

attributes

对于一个tag对象可能具有多个attributes值,比如<a class="sister" href="http://example.com/lacie" id="link2">便有3个属性值。

通过字典和.[attribute]的方式能够获取到属性值

tag的属性可以进行修改、添加和删除等操作,操作方法和字典的一样。

NavigableString(可遍历的字符串)

字符串常被包含在tag内.Beautiful Soup用 NavigableString 类来包装tag中的字符串。

上面通过方法得到了标签里面的内容,那怎么得到标签内部的文字呢?很简单:通过.string方法即可

BeautifulSoup(BS对象)

BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象

因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。

但有时查看它的 .name 属性是很方便的,所以 BeautifulSoup 对象包含了一个值为 “[document]” 的特殊属性 .name

Comment (注释)

Tag , NavigableString , BeautifulSoup 几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象.容易让人担心的内容是文档的注释部分.

Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号,看下面的例子:

使用之前最好先进行一个判断:

代码语言:javascript
复制
if type(soup.a.string) == bs4.element.Comment:  # 如果类型一致
  print(soup.a.string)  # 输出文本内容

首先判断了它的类型,是否为 Comment 类型,然后再进行其他操作,如打印输出。

遍历文档树?

直接子节点
tag的名称

一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。

Beautiful Soup提供了许多操作和遍历子节点的属性,比如直接获取tag的name值:

如果想获取到所有a标签的值,使用find_all方法

contents

contents属相将tag的子节点以列表的形式输出,获取到的是标签中的内容部分

children

返回的不是列表形式,可以通过遍历来进行获取子节点。实际上是以列表类型的迭代器

descendants-子孙节点

.contents.children 属性仅包含tag的直接子节点,.descendants 属性可以对所有tag的子孙节点进行递归循环,和 children类似,我们也需要遍历获取其中的内容。

代码语言:javascript
复制
# 子孙节点

for each in soup.descendants:
    print(each)

结果显示如下内容:

  • html标签的全部内容
  • body标签
代码语言:javascript
复制
<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 class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body></html>
<head><title>The Dormouse's story</title></head>
<title>The Dormouse's story</title>
The Dormouse's story


<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 class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>


<p class="title"><b>The Dormouse's story</b></p>
<b>The Dormouse's story</b>
The Dormouse's story


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

<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
Elsie
,

<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
Lacie
 and

<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
Tillie
;
and they lived at the bottom of a well.


<p class="story">...</p>
...
节点内容

如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容:

如果存在多个子节点,tag就没法确定了,输出的结果就是None

多个节点
strings

repr()方法的使用

stripped_strings

输出的字符串中可能包含了很多的空格或者空行,使用该方法去除多余的空白内容

笔记?:去除空白内容

父节点相关
parent
parents

将某个元素的所有父辈节点通过递归得到

兄弟节点
单个节点

知识点:.next_sibling .previous_sibling 属性

兄弟节点可以理解为和本节点处在统一级的节点

.next_sibling属性获取了该节点的下一个兄弟节点

.previous_sibling则与之相反,如果节点不存在,则返回 None

注意:实际文档中的tag.next_sibling.previous_sibling属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行

全部节点

知识点:.next_siblings .previous_siblings 属性

通过 .next_siblings.previous_siblings 属性可以对当前节点的兄弟节点迭代输出

搜索文档树?

在BS4中搜索文档树?主要是有两种方法:

  • find_all()
  • find()

前者用的比较更为广泛

find_all()
代码语言:javascript
复制
find_all(name, attrs, recursive, text, **kwargs)

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

过滤器贯穿整个搜索的API。它们可以被使用在tag的name中,节点的属性中,字符串或者它们的混合中,具体见下面的实例

传入字符串

直接传入需要查找的某个标签,会将结果以列表的形式展示出来

!!!!!!需要注意的点:

由于HTML中class标签和Python中的class关键字相同,为了不产生冲突,如果遇到要查询class标签的情况,使用class_来代替,这点和XPATH中的写法类似,举个列子:

但是如果使用的是attrs参数,则不用加下划线

传入正则表达式

如果传入的正则表达式作为参数,BS会通过表达式的match()来匹配内容。

比如我们现在想找所有以b开头的标签,这个时候结果应该是<body><b>都被找到,使用的是re模块中的compile()方法

传入列表

如果想同时查找某几个标签,可以通过列表的形式

传入True

True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点

传入方法

如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数

如果这个方法返回 True ,表示当前元素匹配并且被找到,如果不是则反回 False

下面的方法校验了当前元素中包含class属性却不包含id属性,那么返回True

代码语言:javascript
复制
def has_class_no_id(tag):
  return tag.has_attr('class') and not tag.has_attr('id')

将上面的方法传入到find_all方法中,将得到全部的<p>标签,因为它满足上面的要求

keyword

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

  1. 查找id=‘link2’,自动查找id属性
  1. 如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性
  1. 使用多个参数同时指定
  1. 使用class标签过滤,需要加上下划线(同上面的道理)
attrs

该参数用来定义一个字典来搜索包含特殊属性的tag,当然也能搜索普通的属性

text

通过text参数来搜索文档中的字符串内容。与name参数的可选值相同:字符串、正则表达式、列表、True

limit

find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢。如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数。

效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果。

recursive

调用tagfind_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False则BS4不会搜索子标签

find()
代码语言:javascript
复制
find(name,attrs,text,recursive,**kwargs)

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

CSS选择器

在写CSS的时候,类名前加上点,id名前加上#。

使用soup.select()的方法类筛选元素,返回的类型是list

标签名查找
类名查找
id名查找
组合查找

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

  • 标签
  • 属性

直接查找子标签

属性查找

查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。

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

注意点:select 方法返回的都是列表形式的内容,可以遍历获取,通过get_text方法获取具体内容

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-8-2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是BS4
  • 安装bs4
  • 解析器
    • 安装解析器
      • 常用解析器比较
      • 语法
        • 官方解释
          • 提取步骤
            • 快速入门
              • 导入模块
                • 直接输出
                  • 缩进格式化输出-prettify()
                    • 浏览结构化数据-标签
                    • 四大对象种类
                      • Tag(标签)
                        • name
                        • attributes
                      • NavigableString(可遍历的字符串)
                        • BeautifulSoup(BS对象)
                          • Comment (注释)
                          • 遍历文档树?
                            • 直接子节点
                              • tag的名称
                              • contents
                              • children
                            • descendants-子孙节点
                              • 节点内容
                                • 多个节点
                                  • strings
                                  • stripped_strings
                                • 父节点相关
                                  • parent
                                  • parents
                                • 兄弟节点
                                  • 单个节点
                                  • 全部节点
                              • 搜索文档树?
                                • find_all()
                                  • 传入字符串
                                  • 传入正则表达式
                                  • 传入列表
                                  • 传入True
                                  • 传入方法
                                  • keyword
                                  • attrs
                                  • text
                                  • limit
                                  • recursive
                                • find()
                                • CSS选择器
                                  • 标签名查找
                                    • 类名查找
                                      • id名查找
                                        • 组合查找
                                          • 属性查找
                                          领券
                                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档