BS4
Posted Freeman耀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BS4相关的知识,希望对你有一定的参考价值。
Beautiful Soup 库一般被称为bs4库,支持Python3,是我们写爬虫非常好的第三方库。因用起来十分的简便流畅。所以也被人叫做“美味汤”。下文会介绍该库的最基本的使用。
安装 Beautiful Soup
Beautiful Soup 4 通过PyPi发布,所以如果你无法使用系统包管理安装,那么也可以通过easy_install
或 pip
来安装。包的名字是 beautifulsoup4
,这个包兼容Python2和Python3。
$ easy_install beautifulsoup4
$ pip install beautifulsoup4
如果你没有安装 easy_install
或 pip
,那你也可以 下载BS4的源码 ,然后通过setup.py来安装。
$ Python setup.py install
安装解析器
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
下表列出了主要的解析器,以及它们的优缺点:
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup,"html.parser") |
|
|
lxml HTML 解析器 | BeautifulSoup(markup,"lxml") |
|
|
lxml XML 解析器 |
|
|
|
html5lib | BeautifulSoup(markup,"html5lib") |
|
|
推荐使用lxml作为解析器,因为效率更高。在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib,因为那些Python版本的标准库中内置的HTML解析方法不够稳定。
提示:如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,查看 解析器之间的区别 了解更多细节。
这里我们先简单的讲解一下bs4库的使用,暂时不去考虑如何从web上抓取网页,假设我们需要爬去的html是如下这么一段:
html <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 http://example.com/elsie" class="sister" id="link1">Elsie, http://example.com/lacie" class="sister" id="link2">Lacie and http://example.com/tillie" class="sister" id="link3">Tillie; and they lived at the bottom of a well.</p> <p class="story">...</p> </html>
1 #导入bs4模块 2 from bs4 import BeautifulSoup 3 soup = BeautifulSoup(html,‘html.parser‘) 4 #输出结果 5 print(soup.prettify())
结果:
`html <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 http://example.com/elsie" class="sister" id="link1">Elsie, http://example.com/lacie" class="sister" id="link2">Lacie and http://example.com/tillie" class="sister" id="link3">Tillie; and they lived at the bottom of a well. </p> <p class="story"> ... </p> </body> </html>
可以看到bs4库将网页文件变成了一个soup的类型,事实上,bs4库 是解析、遍历、维护、“标签树“的功能库。
通俗一点说就是: bs4库把html源代码重新进行了格式化,从而方便我们对其中的节点、标签、属性等进行操作。
1 #找到文档的title 2 print(soup.title) 3 # <title>The Dormouse‘s story</title> 4 5 #title的name值 6 print(soup.title.name) 7 # u‘title‘ 8 9 #title中的字符串String 10 print(soup.title.string) 11 # u‘The Dormouse‘s story‘ 12 13 #title的父亲节点的name属性 14 print(soup.title.parent.name) 15 # u‘head‘ 16 17 #文档的第一个找到的段落 18 print(soup.p) 19 # <p class="title"><b>The Dormouse‘s story</b></p> 20 21 #找到的p的class属性值 22 print(soup.p[‘class‘]) 23 # u‘title‘ 24 25 #找到a标签 26 print(soup.a) 27 # http://example.com/elsie" id="link1">Elsie 28 29 #找到所有的a标签 30 print(soup.find_all(‘a‘)) 31 # [http://example.com/elsie" id="link1">Elsie, 32 # http://example.com/lacie" id="link2">Lacie, 33 # http://example.com/tillie" id="link3">Tillie] 34 35 #找到id值等于3的a标签 36 print(soup.find(id="link3")) 37 # http://example.com/tillie" id="link3">Tillie
从文档中找到所有<a>标签的链接:
1 for link in soup.find_all(‘a‘): 2 print(link.get(‘href‘)) 3 # http://example.com/elsie 4 # http://example.com/lacie 5 # http://example.com/tillie
从文档中获取所有文字内容:
print(soup.get_text()) The Dormouse‘s story The Dormouse‘s story Once upon a time there were three little sisters; and their names were Elsie, Lacie and Tillie; and they lived at the bottom of a well. ...
对象的种类
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag
,NavigableString,
BeautifulSoup,
Comment
。
-
Tag:和html中的Tag基本没有区别,可以简单上手使用
-
NavigableString: 被包裹在tag内的字符串
-
BeautifulSoup: 表示一个文档的全部内容,大部分的时候可以把他看做一个tag对象,支持遍历文档树和搜索文档树方法。
-
-
Comment:这是一个特殊的NavigableSting对象,在出现在html文档中时,会以特殊的格式输出,比如注释类型。
搜索文档树的最简单的方法就是搜索你想获取tag的的name:
1 soup.head 2 # <head><title>The Dormouse‘s story</title></head> 3 4 soup.title 5 # <title>The Dormouse‘s story</title>
如果你还想更深入的获得更小的tag:例如我们想找到body下的被b标签包裹的部分
1 soup.body.b 2 # <b>The Dormouse‘s story</b>
获取所有的标签,这个时候需要find_all()方法,他返回一个列表类型。
tag=soup.find_all(‘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>] #假设我们要找到a标签中的第二个元素: need = tag[1] #简单吧
子节点
tag的.contents属性可以将tag的子节点以列表的方式输出:
1 head_tag = soup.head 2 head_tag 3 # <head><title>The Dormouse‘s story</title></head> 4 5 head_tag.contents 6 [<title>The Dormouse‘s story</title>] 7 title_tag = head_tag.contents[0] 8 print(title_tag) 9 # <title>The Dormouse‘s story</title> 10 title_tag.contents 11 # [u‘The Dormouse‘s story‘]
- 另外通过tag的 .children生成器,可以对tag的子节点进行循环:
1 for child in title_tag.children: 2 print(child) 3 # The Dormouse‘s story
- 这种方式只能遍历出子节点。如何遍历出子孙节点呢?
子孙节点:比如 head.contents 的子节点是<title>The Dormouse‘s story</title>,这里 title本身也有子节点:‘The Dormouse‘s story’ 。这里的‘The Dormouse‘s story’也叫作head的子孙节点.
1 for child in head_tag.descendants: 2 print(child) 3 # <title>The Dormouse‘s story</title> 4 # The Dormouse‘s story
找到tag下的所有的文本内容
- 如果该tag只有一个子节点(NavigableString类型):直接使用tag.string就能找到。
- 如果tag有很多个子、孙节点,并且每个节点里都string:
我们可以用迭代的方式将其全部找出:
1 for string in soup.strings: 2 print(repr(string)) 3 # u"The Dormouse‘s story" 4 # u‘\n\n‘ 5 # u"The Dormouse‘s story" 6 # u‘\n\n‘ 7 # u‘Once upon a time there were three little sisters; and their names were\n‘ 8 # u‘Elsie‘ 9 # u‘,\n‘ 10 # u‘Lacie‘ 11 # u‘ and\n‘ 12 # u‘Tillie‘ 13 # u‘;\nand they lived at the bottom of a well.‘ 14 # u‘\n\n‘ 15 # u‘...‘ 16 # u‘\n‘
输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings
可以去除多余空白内容:(全部是空格的行会被忽略掉,段首和段末的空白会被删除)
1 for string in soup.stripped_strings: 2 print(repr(string)) 3 # u"The Dormouse‘s story" 4 # u"The Dormouse‘s story" 5 # u‘Once upon a time there were three little sisters; and their names were‘ 6 # u‘Elsie‘ 7 # u‘,‘ 8 # u‘Lacie‘ 9 # u‘and‘ 10 # u‘Tillie‘ 11 # u‘;\nand they lived at the bottom of a well.‘ 12 # u‘...‘
父节点
继续分析文档树,每个tag或字符串都有父节点:被包含在某个tag中
.parent
通过 .parent
属性来获取某个元素的父节点.在例子的文档中,<head>标签是<title>标签的父节点:
1 title_tag = soup.title 2 title_tag 3 # <title>The Dormouse‘s story</title> 4 title_tag.parent 5 # <head><title>The Dormouse‘s story</title></head>
文档title的字符串也有父节点:<title>标签
1 title_tag.string.parent 2 # <title>The Dormouse‘s story</title>
文档的顶层节点比如<html>的父节点是 BeautifulSoup
对象:
1 html_tag = soup.html 2 type(html_tag.parent) 3 # <class ‘bs4.BeautifulSoup‘>
BeautifulSoup
对象的 .parent
是None:
1 print(soup.parent) 2 # None
.parents
通过元素的 .parents
属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents
方法遍历了<a>标签到根节点的所有节点.
1 link = soup.a 2 link 3 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> 4 for parent in link.parents: 5 if parent is None: 6 print(parent) 7 else: 8 print(parent.name) 9 # p 10 # body 11 # html 12 # [document] 13 # None
有关兄弟节点、回退和前进以及等内容和子节点、父节点差不多,详情请参考官方文档。
以上是关于BS4的主要内容,如果未能解决你的问题,请参考以下文章
Python中安装bs4后,pycharm依然报错ModuleNotFoundError: No module named 'bs4'