BeautifulSoup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库,它能够将 HTML 或 XML 转化为可定位的树形结构,并提供了导航、查找、修改功能,它会自动将输入文档转换为 Unicode 编码,输出文档转换为 UTF-8 编码。

BeautifulSoup 支持 Python 标准库中的 HTML 解析器和一些第三方的解析器,默认使用 Python 标准库中的 HTML 解析器,默认解析器效率相对比较低,如果需要解析的数据量比较大或比较频繁,推荐使用更强、更快的 lxml 解析器。

1 安装

1)BeautifulSoup 安装
如果使用 Debain 或 ubuntu 系统,可以通过系统的软件包管理来安装:apt-get install Python-bs4,如果无法使用系统包管理安装,可以使用 pip install beautifulsoup4 来安装。

2)第三方解析器安装
如果需要使用第三方解释器 lxml 或 html5lib,可是使用如下命令进行安装:apt-get install Python-lxml(html5lib)pip install lxml(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格式的文档。
速度慢;
不依赖外部扩展。

2 快速上手

将一段文档传入 BeautifulSoup 的构造方法,就能得到一个文档的对象,可以传入一段字符串或一个文件句柄,示例如下:

1)使用字符串
我们以如下一段 HTML 字符串为例:

  1. html = '''
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>BeautifulSoup学习</title>
  7. </head>
  8. <body>
  9. Hello BeautifulSoup
  10. </body>
  11. </html>
  12. '''

使用示例如下:

  1. from bs4 import BeautifulSoup
  2. #使用默认解析器
  3. soup = BeautifulSoup(html,'html.parser')
  4. #使用 lxml 解析器
  5. soup = BeautifulSoup(html,'lxml')

2)本地文件
还以上面那段 HTML 为例,将上面 HTML 字符串放在 index.html 文件中,使用示例如下:

  1. #使用默认解析器
  2. soup = BeautifulSoup(open('index.html'),'html.parser')
  3. #使用 lxml 解析器
  4. soup = BeautifulSoup(open('index.html'),'lxml')

2.1 对象的种类

BeautifulSoup 将 HTML 文档转换成一个树形结构,每个节点都是 Python 对象,所有对象可以归纳为4种:TagNavigableStringBeautifulSoupComment

1)Tag 对象
Tag 对象与 HTML 或 XML 原生文档中的 tag 相同,示例如下:

  1. soup = BeautifulSoup('<title>BeautifulSoup学习</title>','lxml')
  2. tag = soup.title
  3. tp =type(tag)
  4. print(tag)
  5. print(tp)
  6. #输出结果
  7. '''
  8. <title>BeautifulSoup学习</title>
  9. <class 'bs4.element.Tag'>
  10. '''

Tag 有很多方法和属性,这里先看一下它的的两种常用属性:nameattributes

我们可以通过 .name 来获取 tag 的名字,示例如下:

  1. soup = BeautifulSoup('<title>BeautifulSoup学习</title>','lxml')
  2. tag = soup.title
  3. print(tag.name)
  4. #输出结果
  5. #title

我们还可以修改 tag 的 name,示例如下:

  1. tag.name = 'title1'
  2. print(tag)
  3. #输出结果
  4. #<title1>BeautifulSoup学习</title1>

一个 tag 可能有很多个属性,先看一它的 class 属性,其属性的操作方法与字典相同,示例如下:

  1. soup = BeautifulSoup('<title class="tl">BeautifulSoup学习</title>','lxml')
  2. tag = soup.title
  3. cls = tag['class']
  4. print(cls)
  5. #输出结果
  6. #['tl']

我们还可以使用 .attrs 来获取,示例如下:

  1. ats = tag.attrs
  2. print(ats)
  3. #输出结果
  4. #{'class': ['tl']}

tag 的属性可以被添加、修改和删除,示例如下:

  1. #添加 id 属性
  2. tag['id'] = 1
  3. #修改 class 属性
  4. tag['class'] = 'tl1'
  5. #删除 class 属性
  6. del tag['class']

2)NavigableString 对象
NavigableString 类是用来包装 tag 中的字符串内容的,使用 .string 来获取字符串内容,示例如下:

  1. str = tag.string

可以使用 replace_with() 方法将原有字符串内容替换成其它内容 ,示例如下:

  1. tag.string.replace_with('BeautifulSoup')

3)BeautifulSoup 对象
BeautifulSoup 对象表示的是一个文档的全部内容,它并不是真正的 HTML 或 XML 的 tag,因此它没有 nameattribute 属性,为方便查看它的 name 属性,BeautifulSoup 对象包含了一个值为 [document] 的特殊属性 .name,示例如下:

  1. soup = BeautifulSoup('<title class="tl">BeautifulSoup学习</title>','lxml')
  2. print(soup.name)
  3. #输出结果
  4. #[document]

4)Comment 对象
Comment 对象是一个特殊类型的 NavigableString 对象,它会使用特殊的格式输出,看一下例子:

  1. soup = BeautifulSoup('<title class="tl">Hello BeautifulSoup</title>','html.parser')
  2. comment = soup.title.prettify()
  3. print(comment)
  4. #输出结果
  5. '''
  6. <title class="tl">
  7. Hello BeautifulSoup
  8. </title>
  9. '''

我们前面看的例子中 tag 中的字符串内容都不是注释内容,现在将字符串内容换成注释内容,我们来看一下效果:

  1. soup = BeautifulSoup('<title class="tl"><!--Hello BeautifulSoup--></title>','html.parser')
  2. str = soup.title.string
  3. print(str)
  4. #输出结果
  5. #Hello BeautifulSoup

通过结果我们发现注释符号 <!----> 被自动去除了,这一点我们要注意一下。

2.2 搜索文档树

BeautifulSoup 定义了很多搜索方法,我们来具体看一下。

1)find_all()
find_all() 方法搜索当前 tag 的所有 tag 子节点,方法详细如下:find_all(name=None, attrs={}, recursive=True, text=None,limit=None, **kwargs),来具体看一下各个参数。

name 参数可以查找所有名字为 name 的 tag,字符串对象会被自动忽略掉,示例如下:

  1. soup = BeautifulSoup('<title class="tl">Hello BeautifulSoup</title>','html.parser')
  2. print(soup.find_all('title'))
  3. #输出结果
  4. #[<title class="tl">Hello BeautifulSoup</title>]

attrs 参数定义一个字典参数来搜索包含特殊属性的 tag,示例如下:

  1. soup = BeautifulSoup('<title class="tl">Hello BeautifulSoup</title>','html.parser')
  2. soup.find_all(attrs={"class": "tl"})

调用 find_all() 方法时,默认会检索当前 tag 的所有子孙节点,通过设置参数 recursive=False,可以只搜索 tag 的直接子节点,示例如下:

  1. soup = BeautifulSoup('<html><head><title>Hello BeautifulSoup</title></head></html>','html.parser')
  2. print(soup.find_all('title',recursive=False))
  3. #输出结果
  4. #[]

通过 text 参数可以搜搜文档中的字符串内容,它接受字符串、正则表达式、列表、True,示例如下:

  1. from bs4 import BeautifulSoup
  2. import re
  3. soup = BeautifulSoup('<head>myHead</head><title>BeautifulSoup</title>','html.parser')
  4. #字符串
  5. soup.find_all(text='BeautifulSoup')
  6. #正则表达式
  7. soup.find_all(soup.find_all(text=re.compile('title')))
  8. #列表
  9. soup.find_all(soup.find_all(text=['head','title']))
  10. #True
  11. soup.find_all(text=True)

limit 参数与 SQL 中的 limit 关键字类似,用来限制搜索的数据,示例如下:

  1. soup = BeautifulSoup('<a id="link1" href="http://example.com/elsie">Elsie</a><a id="link2" href="http://example.com/elsie">Elsie</a>','html.parser')
  2. soup.find_all('a', limit=1)

我们经常见到 Python 中 *arg**kwargs 这两种可变参数,*arg 表示非键值对的可变数量的参数,将参数打包为 tuple 传递给函数; **kwargs 表示关键字参数,参数是键值对形式的,将参数打包为 dict 传递给函数。

使用多个指定名字的参数可以同时过滤 tag 的多个属性,如:

  1. soup = BeautifulSoup('<a id="link1" href="http://example.com/elsie">Elsie</a><a id="link2" href="http://example.com/elsie">Elsie</a>','html.parser')
  2. soup.find_all(href=re.compile("elsie"),id='link1')

有些 tag 属性在搜索不能使用,如 HTML5 中的 data-* 属性,示例如下:

  1. soup = BeautifulSoup('<div data-foo="value">foo!</div>')
  2. soup.find_all(data-foo='value')

首先当我在 Pycharm 中输入 data-foo='value' 便提示语法错误了,然后我不管提示直接执行提示 SyntaxError: keyword can't be an expression 这个结果也验证了 data-* 属性在搜索中不能使用。我们可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的 tag,示例如下:

  1. print(soup.find_all(attrs={'data-foo': 'value'}))

2)find()
方法详细如下:find(name=None, attrs={}, recursive=True, text=None,**kwargs),我们可以看出除了少了 limit 参数,其它参数与方法 find_all 一样,不同之处在于:find_all() 方法的返回结果是一个列表,find() 方法返回的是第一个节点,find_all() 方法没有找到目标是返回空列表,find() 方法找不到目标时,返回 None。来看个例子:

  1. soup = BeautifulSoup('<a id="link1" href="http://example.com/elsie">Elsie</a><a id="link2" href="http://example.com/elsie">Elsie</a>','html.parser')
  2. print(soup.find_all('a', limit=1))
  3. print(soup.find('a'))
  4. #输出结果
  5. '''
  6. [<a href="http://example.com/elsie" id="link1">Elsie</a>]
  7. <a href="http://example.com/elsie" id="link1">Elsie</a>
  8. '''

从示例中我们也可以看出,find() 方法返回的是找到的第一个节点。

3)find_parents() 和 find_parent()
find_all() 和 find() 用来搜索当前节点的所有子节点,find_parents() 和 find_parent() 则用来搜索当前节点的父辈节点。

4)find_next_siblings() 和 find_next_sibling()
这两个方法通过 .next_siblings 属性对当前 tag 所有后面解析的兄弟 tag 节点进行迭代,find_next_siblings() 方法返回所有符合条件的后面的兄弟节点,find_next_sibling() 只返回符合条件的后面的第一个tag节点。

5)find_previous_siblings() 和 find_previous_sibling()
这两个方法通过 .previous_siblings 属性对当前 tag 前面解析的兄弟 tag 节点进行迭代,find_previous_siblings() 方法返回所有符合条件的前面的兄弟节点,find_previous_sibling() 方法返回第一个符合条件的前面的兄弟节点。

6)find_all_next() 和 find_next()
这两个方法通过 .next_elements 属性对当前 tag 之后的 tag 和字符串进行迭代,find_all_next() 方法返回所有符合条件的节点,find_next() 方法返回第一个符合条件的节点。

7)find_all_previous() 和 find_previous()
这两个方法通过 .previous_elements 属性对当前节点前面的 tag 和字符串进行迭代,find_all_previous() 方法返回所有符合条件的节点,find_previous() 方法返回第一个符合条件的节点。

2.3 CSS选择器

BeautifulSoup 支持大部分的 CSS 选择器,在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数,即可使用 CSS 选择器的语法找到 tag,返回类型为列表。示例如下:

  1. soup = BeautifulSoup('<body><a id="link1" class="elsie">Elsie</a><a id="link2" class="elsie">Elsie</a></body>','html.parser')
  2. print(soup.select('a'))
  3. #输出结果
  4. #[<a clss="elsie" id="link1">Elsie</a>, <a clss="elsie" id="link2">Elsie</a>]

通过标签逐层查找

  1. soup.select('body a')

找到某个 tag 标签下的直接子标签

  1. soup.select('body > a')

通过类名查找

  1. soup.select('.elsie')
  2. soup.select('[class~=elsie]')

通过 id 查找

  1. soup.select('#link1')

使用多个选择器

  1. soup.select('#link1,#link2')

通过属性查找

  1. soup.select('a[class]')

通过属性的值来查找

  1. soup.select('a[class="elsie"]')

查找元素的第一个

  1. soup.select_one('.elsie')

查找兄弟节点标签

  1. #查找所有
  2. soup.select('#link1 ~ .elsie')
  3. #查找第一个
  4. soup.select('#link1 + .elsie')

Python爬虫(三):BeautifulSoup库的更多相关文章

  1. Python 爬虫三 beautifulsoup模块

    beautifulsoup模块 BeautifulSoup模块 BeautifulSoup是一个模块,该模块用于接收一个HTML或XML字符串,然后将其进行格式化,之后遍可以使用他提供的方法进行快速查 ...

  2. Python爬虫之BeautifulSoup库

    1. BeautifulSoup 1.1 解析库 1)Python标准库 # 使用方法 BeautifulSoup(markup, "html.parser") # 优势 Pyth ...

  3. python爬虫之urllib库(三)

    python爬虫之urllib库(三) urllib库 访问网页都是通过HTTP协议进行的,而HTTP协议是一种无状态的协议,即记不住来者何人.举个栗子,天猫上买东西,需要先登录天猫账号进入主页,再去 ...

  4. python爬虫之urllib库(一)

    python爬虫之urllib库(一) urllib库 urllib库是python提供的一种用于操作URL的模块,python2中是urllib和urllib2两个库文件,python3中整合在了u ...

  5. Python爬虫之selenium库使用详解

    Python爬虫之selenium库使用详解 本章内容如下: 什么是Selenium selenium基本使用 声明浏览器对象 访问页面 查找元素 多个元素查找 元素交互操作 交互动作 执行JavaS ...

  6. python下载安装BeautifulSoup库

    python下载安装BeautifulSoup库 1.下载https://www.crummy.com/software/BeautifulSoup/bs4/download/4.5/ 2.解压到解压 ...

  7. python爬虫之urllib库(二)

    python爬虫之urllib库(二) urllib库 超时设置 网页长时间无法响应的,系统会判断网页超时,无法打开网页.对于爬虫而言,我们作为网页的访问者,不能一直等着服务器给我们返回错误信息,耗费 ...

  8. Python爬虫之BeautifulSoup的用法

    之前看静觅博客,关于BeautifulSoup的用法不太熟练,所以趁机在网上搜索相关的视频,其中一个讲的还是挺清楚的:python爬虫小白入门之BeautifulSoup库,有空做了一下笔记: 一.爬 ...

  9. Mac os 下 python爬虫相关的库和软件的安装

      由于最近正在放暑假,所以就自己开始学习python中有关爬虫的技术,因为发现其中需要安装许多库与软件所以就在这里记录一下以避免大家在安装时遇到一些不必要的坑. 一. 相关软件的安装:   1. h ...

  10. 通过哪吒动漫豆瓣影评,带你分析python爬虫与BeautifulSoup快速入门【华为云技术分享】

    久旱逢甘霖 西安连着几天温度排行全国三甲,也许是<哪吒之魔童降世>的剧组买通了老天,从踩着风火轮的小朋友首映开始,就全国性的持续高温,还好今天凌晨的一场暴雨,算是将大家从中暑边缘拯救回来了 ...

随机推荐

  1. Java中指令重排

    /** * 指令重排:代码执行顺序与预期不一致 (发生在前后行代码无联系时) * 目的:提高性能 * */ public class HappenBefore { private static int ...

  2. NLP(十八) 一维卷积网络IMDB情感分析

    准备 Keras的IMDB数据集,包含一个词集和对应的情感标签 import pandas as pd from keras.preprocessing import sequence from ke ...

  3. HDU 4479 Shortest path 带限制最短路

    题意:给定一个图,求从1到N的递增边权的最短路. 解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每 ...

  4. HDU5461 Largest Point 思维 2015沈阳icpc

    Largest Point Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  5. spring的嵌套事务

    转自http://www.iteye.com/topic/35907 在所有使用 spring 的应用中, 声明式事务管理可能是使用率最高的功能了, 但是, 从我观察到的情况看, 绝大多数人并不能深刻 ...

  6. Linux执行后台work相关

    Linux的后台运行.关闭.查看后台任务 & ctrl+z jobs fg bg kill nohup setsid disown screen 1.& 加在命令的最后,可以把命令放到 ...

  7. kafka topic消息分配partition规则(Java源码)

    我们知道Kafka 的消息通过topic进行分类.topic可以被分为若干个partition来存储消息.消息以追加的方式写入partition,然后以先入先出的顺序读取. 下面是topic和part ...

  8. hive 包含操作(left semi join)(left outer join = in)迪卡尔积

    目前hive不支持 in或not in 中包含查询子句的语法,所以只能通过left join实现. 假设有一个登陆表login(当天登陆记录,只有一个uid),和一个用户注册表regusers(当天注 ...

  9. 解决chrome浏览器崩溃,再次安装不上问题

    上网重新下载了个安装包,发现安装包都打不来 很绝望,查了很多资料 很多人说要删除注册表的东西 但是打开注册表,发现一堆google的东西,手动删根本不现实 在绝望中看到了解决方案:google Upd ...

  10. Python—字符串和常用数据结构

    目录 1. 字符串 2. 列表 2.1 列表的增删改查 2.2 列表的切片和排序 2.3 生成式语法 3. 元组 4.集合 5. 字典 5.1 字典的增删改查 5.2 字典的常见操作 序言:这一章我们 ...