HTML解析库BeautifulSoup4
BeautifulSoup
是一个可以从HTML或XML文件中提取数据的Python库,它的使用方式相对于正则来说更加的简单方便,常常能够节省我们大量的时间。
BeautifulSoup
也是有官方中文文档的:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
安装
BeautifulSoup
的安装也是非常方便的,pip安装即可。
pip install beautifulsoup4
简单例子
以下是一段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>
"""
我们获取的网页数据通常会像上面这样是完全的字符串格式,所以我们首先需要使用BeautifulSoup
来解析这段字符串。然后会获得一个BeautifulSoup
对象,通过这个对象我们就可以进行一系列操作了。
In [1]: from bs4 import BeautifulSoup
In [2]: soup = BeautifulSoup(html_doc)
In [3]: soup.title
Out[3]: <title>The Dormouse's story</title>
In [4]: soup.title.name
Out[4]: 'title'
In [5]: soup.title.string
Out[5]: "The Dormouse's story"
In [6]: soup.title.parent.name
Out[6]: 'head'
In [7]: soup.p
Out[7]: <p class="title"><b>The Dormouse's story</b></p>
In [8]: soup.p['class']
Out[8]: ['title']
In [9]: soup.a
Out[9]: <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
In [10]: soup.find_all('a')
Out[10]:
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
In [11]: soup.find(id="link3")
Out[11]: <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
可以看到,相对于正则来说,操作简单了不止一个量级。
使用
指定解析器
在上面的例子中,我们可以看到在查找数据之前,是有一个解析网页的过程的:
soup = BeautifulSoup(html_doc)
BeautifulSoup
会自动的在系统中选定一个可用的解析器,以下是主要的几种解析器:
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
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格式的文档 | 速度慢不依赖外部扩展 |
由于这个解析的过程在大规模的爬取中是会影响到整个爬虫系统的速度的,所以推荐使用的是lxml
,速度会快很多,而lxml
需要单独安装:
pip install lxml
安装成功后,在解析网页的时候,指定为lxml即可。
soup = BeautifulSoup(html_doc, 'lxml')
提示:如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,所以要指定某一个解析器。
节点对象
BeautifulSoup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:Tag
,NavigableString
,BeautifulSoup
,Comment
。
tag
tag
就是标签的意思,tag
还有许多的方法和属性。
>>> soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
>>> tag = soup.b
>>> type(tag)
<class 'bs4.element.Tag'>
name
每一个
tag
对象都有name
属性,为标签的名字。>>> tag.name
'b'Attributes
在HTML中,
tag
可能有多个属性,所以tag
属性的取值跟字典相同。>>> tag['class']
'boldest'如果某个
tag
属性有多个值,那么返回的则是列表格式。>>> soup = BeautifulSoup('<p class="body strikeout"></p>')
>>> soup.p['class']
["body", "strikeout"]get_text()
通过
get_text()
方法我们可以获取某个tag
下所有的文本内容。In [1]: soup.body.get_text()
Out[1]: "The Dormouse's story\nOnce upon a time there were three little sisters; and their names were\nElsie,\nLacie and\nTillie;\nand they lived at the bottom of a well.\n...\n"
NavigableString
NavigableString
的意思是可以遍历的字符串,一般被标签包裹在其中的的文本就是NavigableString
格式。
In [1]: soup = BeautifulSoup('<p>No longer bold</p>')
In [2]: soup.p.string
Out[2]: 'No longer bold'
In [3]: type(soup.p.string)
Out[3]: bs4.element.NavigableString
BeautifulSoup
BeautifulSoup
对象就是解析网页获得的对象。
Comment
Comment
指的是在网页中的注释以及特殊字符串。
Tag与遍历文档树
tag
对象可以说是BeautifulSoup
中最为重要的对象,通过BeautifulSoup
来提取数据基本都围绕着这个对象来进行操作。
首先,一个节点中是可以包含多个子节点和多个字符串的。例如html
节点中包含着head
和body
节点。所以BeautifulSoup
就可以将一个HTML的网页用这样一层层嵌套的节点来进行表示。
以上方的爱丽丝梦游仙境为例:
contents和children
通过contents
可以获取某个节点所有的子节点,包括里面的NavigableString
对象。获取的子节点是列表格式。
In [1]: soup.head.contents
Out[1]: [<title>The Dormouse's story</title>]
而通过children
同样的是获取某个节点的所有子节点,但是返回的是一个迭代器,这种方式会比列表格式更加的节省内存。
In [1]: tags = soup.head.children
In [2]: tags
Out[2]: <list_iterator at 0x110f76940>
In [3]: for tag in tags:
print(tag)
<title>The Dormouse's story</title>
descendants
上面的contents
和children
获取的是某个节点的直接子节点,而无法获得子孙节点。通过descendants
可以获得所有子孙节点,返回的结果跟children
一样,需要迭代或者转类型使用。
In [1]: len(list(soup.body.descendants))
Out[1]: 19
In [2]: len(list(soup.body.children))
Out[2]: 6
string和strings
我们常常会遇到需要获取某个节点中的文本值的情况,如果这个节点中只有一个字符串,那么使用string
可以正常将其取出。
In [1]: soup.title.string
Out[1]: "The Dormouse's story"
而如果这个节点中有多个字符串的时候,BeautifulSoup
就无法确定要取出哪个字符串了,这时候需要使用strings
。
In [1]: list(soup.body.strings)
Out[1]:
["The Dormouse's story",
'\n',
'Once upon a time there were three little sisters; and their names were\n',
'Elsie',
',\n',
'Lacie',
' and\n',
'Tillie',
';\nand they lived at the bottom of a well.',
'\n',
'...',
'\n']
而使用stripped_strings
可以将全是空白的行去掉。
In [1]: list(soup.body.stripped_strings)
Out[1]:
["The Dormouse's story",
'Once upon a time there were three little sisters; and their names were',
'Elsie',
',',
'Lacie',
'and',
'Tillie',
';\nand they lived at the bottom of a well.',
'...']
父节点parent和parents
有时我们也需要去获取某个节点的父节点,也就是包裹着当前节点的节点。
In [1]: soup.b.parent
Out[1]: <p class="title"><b>The Dormouse's story</b></p>
而使用parents
则可以获得当前节点递归到顶层的所有父辈元素。
In [1]: [i.name for i in soup.b.parents]
Out[1]: ['p', 'body', 'html', '[document]']
兄弟节点
兄弟节点指的就是父节点相同的节点。
next_sibling 和 previous_sibling
兄弟节点选取的方法与当前节点的位置有关,
next_sibling
获取的是当前节点的下一个兄弟节点,previous_sibling
获取的是当前节点的上一个兄弟节点。所以,兄弟节点中排第一个的节点是没有
previous_sibling
的,最后一个节点是没有next_sibling
的。In [51]: soup.head.next_sibling
Out[51]: '\n'
In [52]: soup.head.previos_sibling
In [59]: soup.body.previous_sibling
Out[59]: '\n'next_siblings 和 previous_siblings
相对应的,
next_siblings
获取的是下方所有的兄弟节点,previous_siblings
获取的上方所有的兄弟节点。In [47]: [i.name for i in soup.head.next_siblings]
Out[47]: [None, 'body']
In [48]: [i.name for i in soup.body.next_siblings]
Out[48]: []
In [49]: [i.name for i in soup.body.previous_siblings]
Out[49]: [None, 'head']
find_all()
上方这种直接通过属性来进行访问属性的方法,很多时候只能适用于比较简单的一些场景,所以BeautifulSoup
还提供了搜索整个文档树的方法find_all()
。
需要注意的是,find_all()
方法基本所有节点对象都能调用。
通过name搜索
就像以下演示的,find_all()
可以直接查找出整个文档树中所有的b标签,并返回列表。
>>> soup.find_all('b')
[<b>The Dormouse's story</b>]
而如果传入的是一个列表,则会与列表中任意一个元素进行匹配。可以看到,搜索的结果包含了所有的a标签和b标签。
>>> soup.find_all(["a", "b"])
[<b>The Dormouse's story</b>,
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
通过属性搜索
我们在搜索的时候一般只有标签名是不够的,因为可能同名的标签很多,那么这时候我们就要通过标签的属性来进行搜索。
这时候我们可以通过传递给attrs一个字典参数来搜索属性。
In [1]: soup.find_all(attrs={'class': 'sister'})
Out[1]:
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
可以看到找出了所有class属性为sister的标签。
通过文本搜索
在find_all()
方法中,还可以根据文本内容来进行搜索。
>>> soup.find_all(text="Elsie")
[u'Elsie']
>>> soup.find_all(text=["Tillie", "Elsie", "Lacie"])
[u'Elsie', u'Lacie', u'Tillie']
可见找到的都是字符串对象,如果想要找到包含某个文本的tag
,加上tag
名即可。
>>> soup.find_all("a", text="Elsie")
[<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]
限制查找范围为子节点
find_all()
方法会默认的去所有的子孙节点中搜索,而如果将recursive
参数设置为False,则可以将搜索范围限制在直接子节点中。
>>> soup.html.find_all("title")
[<title>The Dormouse's story</title>]
>>> soup.html.find_all("title", recursive=False)
[]
通过正则表达式来筛选查找结果
在BeautifulSoup
中,也是可以与re
模块进行相互配合的,将re.compile编译的对象传入find_all()
方法,即可通过正则来进行搜索。
In [1]: import re
In [2]: tags = soup.find_all(re.compile("^b"))
In [3]: [i.name for i in tags]
Out[3]: ['body', 'b']
可以看到,找到了标签名是以'b'开头的两个标签。
同样的,也能够以正则来筛选tag
的属性。
In [1]: soup.find_all(attrs={'class': re.compile("si")})
Out[1]:
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
CSS选择器
在BeautifulSoup
中,同样也支持使用CSS选择器来进行搜索。使用select()
,在其中传入字符串参数,就可以使用CSS选择器的语法来找到tag。
>>> soup.select("title")
[<title>The Dormouse's story</title>]
>>> soup.select("p > a")
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
HTML解析库BeautifulSoup4的更多相关文章
- python3解析库BeautifulSoup4
Beautiful Soup是python的一个HTML或XML的解析库,我们可以用它来方便的从网页中提取数据,它拥有强大的API和多样的解析方式. Beautiful Soup的三个特点: Beau ...
- 【转】python3解析库lxml
转自:http://www.cnblogs.com/zhangxinqi/p/9210211.html 阅读目录 1.python库lxml的安装 2.XPath常用规则 (1)读取文本解析节点 (2 ...
- python3解析库pyquery
pyquery是一个类似jquery的python库,它实现能够在xml文档中进行jQuery查询,pyquery使用lxml解析器进行快速在xml和html文档上操作,它提供了和jQuery类似的语 ...
- 爬虫 解析库re,Beautifulsoup,
re模块 点我回顾 Beautifulsoup模块 #安装 Beautiful Soup pip install beautifulsoup4 #安装解析器 Beautiful Soup支持Pytho ...
- bs4解析库
beautifulsoup4 bs4解析库是灵活又方便的网页解析库,处理高效,支持多种解析器.利用它不用编写正则表达式即可方便地实现网页的提取 要解析的html标签 from bs4 import B ...
- Python爬虫【解析库之beautifulsoup】
解析库的安装 pip3 install beautifulsoup4 初始化 BeautifulSoup(str,"解析库") from bs4 import BeautifulS ...
- 解析库之re,Beautifulsoup
本篇导航: 介绍 基本使用 遍历文档树 搜索文档树 总结 re模块在之前的python进阶中有讲过不再做过多的阐述,本篇为BeautifulSoup库的分析 20.collections模块和 ...
- 爬虫模块介绍--Beautifulsoup (解析库模块,正则)
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时 ...
- Python3编写网络爬虫06-基本解析库Beautiful Soup的使用
二.Beautiful Soup 简介 就是python的一个HTML或XML的解析库 可以用它来很方便的从网页中提取数据 0.1 提供一些简单的 python式的函数来处理导航,搜索,修改分析树等功 ...
随机推荐
- P3052 [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper 状压dp
这个状压dp其实很明显,n < 18写在前面了当然是状压.状态其实也很好想,但是有点问题,就是如何判断空间是否够大. 再单开一个g数组,存剩余空间就行了. 题干: 题目描述 A little k ...
- bzoj1997 [Hnoi2010]Planar——2-SAT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1997 神奇的经典2-SAT问题! 对于两个相交的区间,只能一里一外连边,所以可以进行2-SA ...
- 3.4 目录和spooling
文件管理部分主要讲文件目录.文件目录它是用于检索文件的.文件目录它是一种文件系统实现按0存取的一种重要手段.一个文件目录它由若干个目录项组成的.每一个目录项它记录了一个文件的相关信息.这个文件信息指明 ...
- RT-Thread 设备驱动I2C浅析及使用
由于 I2C 可以控制多从机的属性,设备驱动模型分为 I2C总线设备(类似与Linux里面的I2C适配器) + I2C从设备: 系统I2C设备驱动主要实现 I2C 总线设备驱动,而具体的I2C 从设 ...
- ios-判断手机上是否安装了某个App
方法一 1.获取手机中安装的所有App 1.1.runtime中的方法,所以要导入 #include <objc/runtime.h> 1.2.在 AppDel ...
- Android 显示意图和隐式意图的区别
意图在android的应用开发中是很重要的,明白了意图的作用和使用后,对开发会有很大帮助.如果没有把意图搞懂,以后开发应用会感觉缺些什么. 意图的作用: 1.激活组件 ...
- mysql索引的操作
一.创建和查看普通索引 这是最基本的索引类型,而且它没有唯一性之类的限制 1.创建表时创建普通索引 CREATE TABLE table_name( 属性名 数据类型, ... 属性名 数据类型, I ...
- 控制台——EventLog实现事件日志操作
我们应该如何通过写代码的方式向其中添加“日志”呢? 在操作之前,先明确几个概念: 1:事件日志名(logName):“事件查看器”中的每一项,如“应用程序”.“Internet Explorer”.“ ...
- 转载:使用FileReader对象的readAsDataURL方法来读取图像文件
文章转载自:http://blog.okbase.net/jquery2000/archive/1296.html: FileReader对象的readAsDataURL方法可以将读取到的文件编码成D ...
- Python 时间处理---------笔记
时区处理&格式化 import pytz from datetime import datetime # 设置时区 timezone = pytz.timezone('Asia/Shangha ...