Python 爬虫之Beautiful Soup模块使用指南


Posted in Python onJuly 05, 2018

爬取网页的流程一般如下:

  1. 选着要爬的网址(url)
  2. 使用 python 登录上这个网址(urlopen、requests 等)
  3. 读取网页信息(read() 出来)
  4. 将读取的信息放入 BeautifulSoup
  5. 使用 BeautifulSoup 选取 tag 信息等

可以看到,页面的获取其实不难,难的是数据的筛选,即如何获取到自己想要的数据。本文就带大家学习下 BeautifulSoup 的使用。

BeautifulSoup 官网介绍如下:

Beautiful Soup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库,它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方式,能够帮你节省数小时甚至数天的工作时间。

1 安装

可以利用 pip 直接安装:

$ pip install beautifulsoup4

BeautifulSoup 不仅支持 HTML 解析器,还支持一些第三方的解析器,如 lxml,XML,html5lib 但是需要安装相应的库。如果我们不安装,则 Python 会使用 Python 默认的解析器,其中 lxml 解析器更加强大,速度更快,推荐安装。

$ pip install html5lib
$ pip install lxml

2 BeautifulSoup 的简单使用

首先我们先新建一个字符串,后面就以它来演示 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 href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""

使用 BeautifulSoup 解析这段代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出:

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(html_doc, "lxml")
>>> print(soup.prettify())

篇幅有限,输出结果这里不再展示。

另外,这里展示下几个简单的浏览结构化数据的方法:

>>> soup.title
<title>The Dormouse's story</title>
>>> soup.title.name
'title'
>>> soup.title.string
"The Dormouse's story"
>>> soup.p['class']
['title']
>>> soup.a
<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>
>>> soup.find_all('a')
[<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link3">Tillie</a>]
>>> soup.find(id='link1')
<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>

3 对象的种类

Beautiful Soup 将复杂 HTML 文档转换成一个复杂的树形结构,每个节点都是 Python 对象,所有对象可以归纳为 4 种: Tag、NavigableString、BeautifulSoup、Comment 。

3.1 Tag

Tag通俗点讲就是 HTML 中的一个个标签,像上面的 div,p,例如:

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

可以利用 soup 加标签名轻松地获取这些标签的内容。

>>> print(soup.p)
<p class="title"><b>The Dormouse's story</b></p>
>>> print(soup.title)
<title>The Dormouse's story</title>

不过有一点是,它查找的是在所有内容中的第一个符合要求的标签,如果要查询所有的标签,我们在后面进行介绍。

每个 Tag 有两个重要的属性 name 和 attrs,name 指标签的名字或者 tag 本身的 name,attrs 通常指一个标签的 class。

>>> print(soup.p.name)
p
>>> print(soup.p.attrs)
{'class': ['title']}

3.2 NavigableString

NavigableString:获取标签内部的文字,如,soup.p.string。

>>> print(soup.p.string)
The Dormouse's story

3.3 BeautifulSoup

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

3.4 Comment

Comment:Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。

>>> markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
>>> soup = BeautifulSoup(markup)
>>> comment = soup.b.string
>>> print(comment)
Hey, buddy. Want to buy a used parser?
>>> type(comment)
<class 'bs4.element.Comment'>

b 标签里的内容实际上是注释,但是如果我们利用 .string 来输出它的内容,我们发现它已经把注释符号去掉了,所以这可能会给我们带来不必要的麻烦。

这时候我们可以先判断了它的类型,是否为 bs4.element.Comment 类型,然后再进行其他操作,如打印输出等。

4 搜索文档树

BeautifulSoup 主要用来遍历子节点及子节点的属性,并提供了很多方法,比如获取 子节点、父节点、兄弟节点等,但通过实践来看,这些方法用到的并不多。我们主要用到的是从文档树中搜索出我们的目标。

通过点取属性的方式只能获得当前文档中的第一个 tag,例如,soup.li。如果想要得到所有的<li> 标签,就需要用到 find_all(),find_all() 方法搜索当前 tag 的所有 tag 子节点,并判断是否符合过滤器的条件 find_all() 所接受的参数如下:

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

4.1 按 name 搜索

可以查找所有名字为 name 的 tag,字符串对象会被自动忽略掉。

>>> soup.find_all('b')
[<b>The Dormouse's story</b>]
>>> soup.find_all('a')
[<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link3">Tillie</a>]

4.2 按 id 搜索

如果文档树中包含一个名字为 id 的参数,其实在搜索时会把该参数当作指定名字 tag 的属性来搜索:

>>> soup.find_all(id='link1')
[<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>]

4.3 按 attr 搜索

有些 tag 属性在搜索不能使用,比如 HTML5 中的 data-* 属性,但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的 tag。

其实 id 也是一个 attr:

>>> soup.find_all(attrs={'id':'link1'})
[<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>]

4.4 按 CSS 搜索

按照 CSS 类名搜索 tag 的功能非常实用,但标识 CSS 类名的关键字 class 在 Python 中是保留字,使用 class 做参数会导致语法错误。因此从 Beautiful Soup 的 4.1.1 版本开始,可以通过 class_ 参数搜索有指定 CSS 类名的 tag:

>>> soup.find_all(class_='sister')
[<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link3">Tillie</a>]

4.5 string 参数

通过 string 参数可以搜搜文档中的字符串内容。与 name 参数的可选值一样,string 参数接受字符串、正则表达式、列表、True。

>>> soup.find_all('a', string='Elsie')
[<a class="sister" href="http://example.com/elsie" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="link1">Elsie</a>]

4.6 recursive 参数

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

4.6 find() 方法

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

4.7 get_text() 方法

如果只想得到 tag 中包含的文本内容,那么可以用 get_text() 方法,这个方法获取到 tag 中包含的所有文本内容。

>>> soup.find_all('a', string='Elsie')[0].get_text()
'Elsie'
>>> soup.find_all('a', string='Elsie')[0].string
'Elsie'

至此,Beautiful Soup 的常用使用方法已讲完,若果想了解更多内容,建议看下官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/。

总结

本篇主要带大家了解了 Beautiful Soup,结合一些小例子,相信大家对 Beautiful Soup 已不再陌生,下回会带大家结合 Beautiful Soup 进行爬虫的实战,欢迎继续关注!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python服务器端收发请求的实现代码
Sep 29 Python
Python中取整的几种方法小结
Jan 06 Python
flask框架视图函数用法示例
Jul 19 Python
Python可视化mhd格式和raw格式的医学图像并保存的方法
Jan 24 Python
python爬取微信公众号文章的方法
Feb 26 Python
Django 多环境配置详解
May 14 Python
python实现字典嵌套列表取值
Dec 16 Python
如何利用pygame实现简单的五子棋游戏
Dec 29 Python
如何在python中判断变量的类型
Jul 29 Python
Python 保存加载mat格式文件的示例代码
Aug 04 Python
Python wordcloud库安装方法总结
Dec 31 Python
Python OpenCV超详细讲解基本功能
Apr 02 Python
Python实现模拟登录网易邮箱的方法示例
Jul 05 #Python
python selenium自动上传有赞单号的操作方法
Jul 05 #Python
python实现爬取图书封面
Jul 05 #Python
Python定义二叉树及4种遍历方法实例详解
Jul 05 #Python
Python使用pyodbc访问数据库操作方法详解
Jul 05 #Python
如何优雅地处理Django中的favicon.ico图标详解
Jul 05 #Python
解决pandas中读取中文名称的csv文件报错的问题
Jul 04 #Python
You might like
php miniBB中文乱码问题解决方法
2008/11/25 PHP
写php分页时出现的Fatal error的解决方法
2011/04/18 PHP
PHP 小心urldecode引发的SQL注入漏洞
2011/10/27 PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
2013/07/15 PHP
理解PHP中的stdClass类
2014/04/18 PHP
php+xml编程之xpath的应用实例
2015/01/24 PHP
php实现的美国50个州选择列表实例
2015/04/20 PHP
利用PHP判断是手机移动端还是PC端访问的函数示例
2017/12/14 PHP
jquery向.ashx文件post中文乱码问题的解决方法
2011/03/28 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
2012/12/26 Javascript
Json对象与Json字符串互转(4种转换方式)
2013/03/27 Javascript
js hover 定时器(实例代码)
2013/11/12 Javascript
ie7+背景透明文字不透明超级简单的实现方法
2014/01/17 Javascript
jQuery Real Person验证码插件防止表单自动提交
2015/11/06 Javascript
详解Node.js中的事件机制
2016/09/22 Javascript
JS树形菜单组件Bootstrap TreeView使用方法详解
2016/12/21 Javascript
解决nodejs中使用http请求返回值为html时乱码的问题
2017/02/18 NodeJs
详解Vue中watch的高级用法
2018/05/02 Javascript
JS实现图片上传多次上传同一张不生效的处理方法
2018/08/06 Javascript
解决layui富文本编辑器图片上传无法回显的问题
2019/09/18 Javascript
小程序实现上传视频功能
2020/08/18 Javascript
[04:52]2015国际邀请赛LGD战队晋级之路
2015/08/14 DOTA
python将xml xsl文件生成html文件存储示例讲解
2013/12/03 Python
Python 常用 PEP8 编码规范详解
2017/01/22 Python
python urllib urlopen()对象方法/代理的补充说明
2017/06/29 Python
使用Python爬虫库requests发送表单数据和JSON数据
2020/01/25 Python
用python实现一个简单的验证码
2020/12/09 Python
Chain Reaction Cycles俄罗斯:世界上最大的在线自行车商店
2019/08/27 全球购物
企业项目策划书
2014/01/11 职场文书
股份转让协议书范本
2015/01/27 职场文书
刑事起诉书范文
2015/05/19 职场文书
工作简报格式范文
2015/07/21 职场文书
毕业季聚会祝酒词!
2019/07/04 职场文书
掌握这项技巧,一年阅读300本书不是梦
2019/09/12 职场文书
Linux7.6二进制安装Mysql8.0.27详细操作步骤
2021/11/27 MySQL
Oracle查看表空间使用率以及爆满解决方案详解
2022/07/23 Oracle