上一篇分享了正则表达式的使用,相信大家对正则也已经有了一定的了解。它可以针对任意字符串做任何的匹配并提取所需信息。

但是我们爬虫基本上解析的都是html或者xml结构的内容,而非任意字符串。正则表达式虽然很强大灵活,但是对于html这样结构复杂的来说,写pattern的工作量会大大增加,并且有任意一处出错都得不到匹配结果,比较麻烦。

本篇将介绍一款针对html和xml结构,操作简单并容易上手的解析利器—BeautifulSoup。

BeautifulSoup的介绍

第一次使用BeautifulSoup的时候就在想:这个名字有什么含义吗?美味的汤?于是好信也在网上查了一下。

来看,官方文档是这么解释的:

BeautifulSoup: We called him Tortoise because he taught us”

意思是我们叫他乌龟因为他教了我们,当然这里Tortoise是Taught us的谐音。BeautifulSoup这个词来自于《爱丽丝漫游仙境》,意思是“甲鱼汤”。上面那个官方配图也是来自于《爱丽丝漫游仙境》,看来是没跑了,估计是作者可能很喜欢这部小说吧,因而由此起了这个名字。

好,让我们看看真正的BeautifulSoup是什么?

BeautifulSoup是Python语言中的模块,专门用于解析html/xml,非常适合像爬虫这样的项目。它有如下几个使其强大的特点:

它提供了几个超级简单的方法和Pythonic的语句来实现强大的导航、搜索、修改解析树的功能。

它会自动把将要处理的文档转化为Unicode编码,并输出为utf-8的编码,不需要你再考虑编码的问题。

支持Python标准库中的HTML解析器,还支持第三方的模块,如 lxml解析器 。

BeautifulSoup的安装

目前BeautifulSoup的最新发型版本是BeautifulSoup4,在Python中以bs4模块引入。

博主使用的Python3.x,可以使用 pip3 install bs4 来进行安装,也可以通过官方网站下载来安装,链接:https://www.crummy.com/software/BeautifulSoup/,具体安装步骤不在此叙述了。

以为安装完了吗?还没有呢。

上面介绍BeautifulSoup的特点时说到了,BeautifulSoup支持Python标准库的解析器html5lib,纯Python实现的。除此之外,BeautifulSoup还支持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 HTML解析器BeautifulSoup(markup, ["lxml",   "xml"])

BeautifulSoup(markup, "xml")

html5libBeautifulSoup(markup, "html5lib")

推荐使用lxml作为解析器,lxml是用C语言库来实现的,因此效率更高。在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定。

BeautifulSoup的文档对象创建

首先引入bs4库,也就是BeautifulSoup在Python中的模块。

from bs4 import BeautifulSoup

好了,我们来看一下官方提供的例子,这段例子引自《爱丽丝漫游记》。

html_doc ="""

The Dormouse's story

The Dormouse's story

Once upon a time there were three little sisters; and their names were

Elsie,

Lacie

andTillie;

and they lived at the bottom of a well.

...

"""

假设以上html_doc就是我们已经下载的网页,我们需要从中解析并获取感兴趣的内容。

首先的首先,我们需要创建一个BeautifulSoup的文档对象,依据不同需要可以传入“字符串”或者“一个文件句柄”。

传入“字符串”

soup = BeautifulSoup(html_doc)

传入“文件句柄”,打开一个本地文件

soup = BeautifulSoup(open("index.html"))

文档首先被转换为Unicode,如果是解析html文档,直接创建对象就可以了(像上面操作那样),这时候BeautifulSoup会选择一个最合适的解析器对文档进行解析。

但同时,BeautifulSoup也支持手动选择解析器,根据指定解析器进行解析(也就是我们安装上面html5lib和lxml的原因)。

手动指定解析器如下:

soup = BeautifulSoup(html_doc, "lxml")

如果仅是想要解析HTML文档,只要用文档创建 BeautifulSoup 对象就可以了。Beautiful Soup会自动选择一个解析器来解析文档。但是还可以通过参数指定使用那种解析器来解析当前文档。

BeautifulSoup 第一个参数应该是要被解析的文档字符串或是文件句柄,第二个参数用来标识怎样解析文档。如果第二个参数为空,那么Beautiful Soup根据当前系统安装的库自动选择解析器,解析器的优先数序: lxml, html5lib, Python标准库。在下面两种条件下解析器优先顺序会变化:

要解析的文档是什么类型: 目前支持, “html”, “xml”, 和 “html5”

指定使用哪种解析器: 目前支持, “lxml”, “html5lib”, 和 “html.parser”

BeautifulSoup的对象种类

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

NavigableString

BeautifulSoup

Comment

Tag就是html或者xml中的标签,BeautifulSoup会通过一定的方法自动寻找你想要的指定标签。查找标签这部分会在后面“遍历查找树”和“搜索查找树”中介绍,这里仅介绍对象。

soup = BeautifulSoup('Extremely bold')

tag=soup.b

type(tag)

>>>

Tag标签下也有对象,有两个重要的属性对象:name和attributes。

Name

Name就是标签tag的名字,以下简单操作便可获取。

tag.name

>>> u'b'

Attributes

我们都知道一个标签下可能有很多属性,比如上面那个标签b有class属性,属性值为boldest,那么我们如何获取这个属性值呢?

其实标签的属性操作和Python中的字典操作一样的,如下:

tag['class']

>>> u'boldest'

也可以通过“点”来获取,比如:

tag.attrs

>>> {u'class': u'boldest'}

NavigableString是可遍历字符串的意思,其实就是标签内包括的字符串,在爬虫里也是我们主要爬取的对象之一。

在BeautifulSoup中可以非常简单的获取标签内这个字符串。

tag.string

>>> u'Extremely bold'

就这么简单的完成了信息的提取,简单吧。要说明一点,tag中包含的字符串是不能编辑的,但是可以替换。

tag.string.replace_with("No longer bold")

tag

>>>

No longer bold

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

soup.name

>>> u'[document]'

BeautifulSoup对象不是一个真正的tag,没有name和attributes,但是却可以查看它的name属性。如上所示,“[document]”为BeautifulSoup文档对象的特殊属性名字。

还有一些对象也是我们需要特殊注意的,就是注释。其实comment对象是一个特殊类型的NavigableString对象,请看下面。

markup = ""

soup = BeautifulSoup(markup)

comment = soup.b.string

type(comment)

>>>

comment

>>> u'Hey, buddy. Want to buy a used parser'

这和NavigableString的使用是一样,同样使用 .string 对标签内字符串进行提取。但是,请看上面comment这个例子,里面字符串是一个comment,有这样的格式,一样使用了 .string对其进行提取,得到的结果是去掉了comment标志的里面的字符串。这样的话,当我们并不知道它是否是comment,如果得到以上的结果很有可能不知道它是个comment。

因此,这可能会让我们得到我们不想要的comment,扰乱我们的解析结果。

为了避免这种问题的发生,可以在使用之前首先通过以下代码进行一个简单的判断,然后再进行其它操作。

iftype(soup.b.string)==bs4.element.Comment:

print(soup.b.string)

BeautifulSoup的遍历文档树

仍然用最开始的《爱丽丝》中的一段话作为例子。

子节点

子节点有 .contents 和 .children 两种用法。

contents

content属性可以将标签所有子节点以列表形式返回。

#

The Dormouse's story

print(soup.head.contents)

>>> [title>The Dormouse's story]

这样就可以返回一个子节点标签了。当然你也可以通过soup.title来实现,但是当文档结构复杂的时候,比如有不止一个title的话,那这样就不如contents使用来的快了。

head下只有一个标签title,那么如果我们查看一下body下的子标签。

print(soup.body.contents)

>>>

['\n',

The Dormouse's story

, '\n',

Once upon a time there were three little sisters; and their names were

Elsie,

Lacie

andTillie;

and they lived at the bottom of a well.

, '\n',

...

, '\n']

你会发现这些子节点列表中有很多“\n”,这是因为它把空格包括进去了,所以这里需要注意一下。

children

也可以通过 .chidren 得到相同的结果,只不过返回的children是一个生成器(generator),而不是一个列表。

print(soup.body.children)

>>>

看到这是一个生成器,因此我们可以for..in..进行遍历,当然也可以得到以上同样的结果。

forchildinsoup.body.children: print(child)

子孙节点

子孙节点使用.descendants属性。如果子节点可以直接获取标签的直接子节点,那么子孙节点则可以获取所有子孙节点,注意说的是所有,也就是说孙子的孙子都得给我找出来,下用面开一个例子。

for child in head_tag.descendants:    print(child)

>>>

The Dormouse's story

>>> The Dormouse's stor

title是head的子节点,而title中的字符串是title的子节点,title和title所包含的字符串都是head的子孙节点,因此被循环递归的查找出来。.descendants 的用法和 .children 是一样的,会返回一个生成器,需要for..in..进行遍历。

父节点

父节点使用 .parents 属性实现,可以得到父辈的标签。

title_tag = soup.title

title_tag

>>>

The Dormouse's story

title_tag.parent

>>>

The Dormouse's story

title_tag.parent.name

>>> head

获得全部父节点则使用.parents属性实现,可以循环得到所有的父辈的节点。

link = soup.a

for parent in link.parents:    if parent is None:        print(parent)    else:        print(parent.name)

>>>

p

body

html

[document]

None

可以看到a节点的所有父辈标签都被遍历了,包括BeautifulSoup对象本身的[document]。

兄弟节点

兄弟节点使用.next_sibling和.previous_sibling属性。

兄弟嘛,不难理解自然就是同等地位的节点了,其中next_sibling 获取下一个兄弟节点,而previous_sibling 获取前一个兄弟节点。

a_tag = soup.find("a", id="link1")

a_tag.next_sibling

>>> ,

a_tag.previous_element

>>>

Once upon a time there were three little sisters; and their names were

兄弟节点可以通过 .next_siblings 和 .previous.sibling 获取所有前后兄弟节点,同样需要遍历获取每个元素。

回退和前进

当然还有一些其它用法,如回退和前进.next_element和.previous_element,它是针对所有节点的回退和前进,不分辈分。

a_tag = soup.find("a", id="link1")

a_tag

>>>

Elsie,

a_tag.next_element

>>> Elsie

a_tag.previous_element

>>>

Once upon a time there were three little sisters; and their names were

因为使用了回退,将会寻找下一个节点对象而不分辈分,那么这个标签的下一个节点就是它的子节点Elsie,而上一个节点就是上一个标签的字符串对象。find用法会在后续搜索文档树里面详细介绍。

回退和前进也可以寻找所有的前后节点,使用.next_elements和.previous_elements。

for elem in last_a_tag.next_elements:

if elem.nameisNone:continue

print(elem.name)

>>>

a

a

p

返回对象同样是生成器,需要遍历获得元素。其中使用了if判断去掉了不需要的None。

节点内容

前面提到过NavigableString对象的 .string 用法,这里在文档遍历再次体会一下其用法。

如果tag只有一个NavigableString 类型子节点,那么这个tag可以使用.string得到子节点,就像之前提到的一样。而如果一个tag里面仅有一个子节点(比如tag里tag的字符串节点),那么这个tag也可以使用.string方法,输出结果与当前唯一子节点的.string结果相同(如上所示)。

title_tag.string

>>> u'The Dormouse's story'

head_tag.contents

>>> [

The Dormouse's story]

head_tag.string

>>> u'The Dormouse's story'

但是如果这个tag里面有多个节点,那就不灵了。因为tag无法确定该调用哪个节点,如下面这种。

print(soup.html.string)

>>> None

如果tag中包含多个字符串,可以使用 .strings 来循环获取,输出的字符串中可能包含了很多空格或空行,使用.stripped_strings可以去除多余空白内容。

上面提介绍的都是如何遍历各个节点,下面我们看看如何搜索我们我们真正想获取的内容,如标签属性等。

BeautifulSoup的搜索文档树

搜索文档树有很多种用法,但使用方法都基本一致。这里只选择介绍一种.find_all。

find_all()

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

find_all() 方法可以搜索当前标签下的子节点,并会经过过滤条件判断是否符合标准,先随便看个例子。

soup.find_all("a")

>>>

[Elsie,

Lacie,

Tillie]

soup.find_all(id="link2")

>>>

[Lacie]

通过以上例子,可以发现,我们只要设定好我们的过滤条件,便可轻松的解析我们想要的内容。这些条件如何设定呢?

就是通过find_all()的这些参数来设置的,让我们来看看。

Name参数

name参数就是标签的名字,如上面的例子寻找所有标签,name参数可以是字符串、True、正则表达式、列表、甚至具体方法。

下面举个正则表达式的例子。

importre

soup =BeautifulSoup(html_doc, 'lxml')fortag insoup.find_all(re.compile("^t")):print(tag.name)

>>> title

可以看到正则表达式的意思是匹配任何以“t”开头的标签名称,就只有title一个。

使用“True”会匹配任何值,使用“列表”会匹配列表中所有的标签项,如果没有合适的过滤条件,还可以自定义一个“方法”。

Keyword参数

就如同Python中的关键字参数一样,我们可以搜索指定的标签属性来定位标签。

soup.find_all(id='link2')

>>>

[Lacie]

找到了id属性为link2的标签。

soup.find_all(href=re.compile("elsie"))

>>>

[Elsie]

找到了href属性里含有“elsie”字样的标签。

也可以同时定义多个关键字条件来过滤匹配结果。

soup.find_all(href=re.compile("elsie"), id='link1')

>>>

[three]

text参数

通过text参数可以搜索匹配的字符串内容,与name的用法相似,也可以使用字符串、True、正则表达式、列表、或者具体方法。

soup.find_all(text="Elsie")>>> [u'Elsie']

soup.find_all(text=re.compile("Dormouse")) >>>

[u"The Dormouse's story", u"The Dormouse's story"]

limit参数

limit参数可以限制返回匹配结果的数量,看下面这个例子。

soup.find_all("a", limit=2)

>>>

[Elsie,

Lacie]

文档中本来有三个标签,但是通过限制只得到了两个。

recursive参数

find_all()会寻找符合匹配条件的所有子孙节点,如果我们只想找直接的子节点,就可以设置recursive参数来进行限制,recursive=False。

soup.html.find_all("title")

>>> [

The Dormouse's story]

soup.html.find_all("title", recursive=False)

>>> [ ]

上面是两种使用recursive和没有使用recursive的情况,可以发现它的作用。

以上就是find_all()所有参数的介绍,其它方法如find(),find_parents()等更多方法与find_all()基本一致,可以举一反三。

总结

以上就是BeautifulSoup的使用方法介绍,主要记住三个部分内容:

BeautifulSoup对象种类

BeautifulSoup的遍历文档树

BeautifulSoup的搜索文档树

python版本回退_Python爬虫之BeautifulSoup解析之路相关推荐

  1. python bs4模块_python爬虫之Beautifulsoup模块用法详解

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

  2. python网页结构分析_Python爬虫解析网页的4种方式 值得收藏

    用Python写爬虫工具在现在是一种司空见惯的事情,每个人都希望能够写一段程序去互联网上扒一点资料下来,用于数据分析或者干点别的事情. 我们知道,爬虫的原理无非是把目标网址的内容下载下来存储到内存中, ...

  3. python爬虫beautifulsoup爬当当网_Python爬虫包 BeautifulSoup 递归抓取实例详解_python_脚本之家...

    Python爬虫包 BeautifulSoup  递归抓取实例详解 概要: 爬虫的主要目的就是为了沿着网络抓取需要的内容.它们的本质是一种递归的过程.它们首先需要获得网页的内容,然后分析页面内容并找到 ...

  4. python爬虫提取a标签_Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释

    一.Tag(标签)对象 1.Tag对象与XML或HTML原生文档中的tag相同. from bs4 import BeautifulSoup soup = BeautifulSoup('Extreme ...

  5. python自带网页解析器_Python爬虫Chrome网页解析工具-XPath Helper

    之前就说过Python爬虫中Xpath的用法,相信每一个写爬虫.或者是做网页分析的人,都会因为在定位.获取XPath路径上花费大量的时间,在没有这些辅助工具的日子里,我们只能通过搜索HTML源代码,定 ...

  6. python tag对象下有多个标签、属性_Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释...

    Apple iPhone 11 (A2223) 128GB 黑色 移动联通电信4G手机 双卡双待 4999元包邮 去购买 > 如何利用Python爬虫库BeautifulSoup获取对象(标签) ...

  7. python获取标签属性值_Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释

    更多python教程请到: 菜鸟教程www.piaodoo.com 人人影视www.sfkyty.com 16影视www.591319.com 星辰影院www.591319.com 一.Tag(标签) ...

  8. python安全攻防---爬虫基础---BeautifulSoup解析

    0x01 基础 使用bs4首先要安装,安装后导入 import bs4 bs对象有两个方法,一个是find,另一个是find_all find(标签名,属性值):只返回一个,返回也是bs对象,可以继续 ...

  9. 1. 爬虫之Beautifulsoup解析库在线解析图片验证码

    1. 解析库beautifulsoup 1.1 介绍 BeautifulSoup是一个可以从HTML或XML文件中提取数据的Python库. 官方文档: https://www.crummy.com/ ...

最新文章

  1. kali系统破解WPA密码实战
  2. 右边菜单_Excel – 如何始终显示下拉菜单右边的小箭头?
  3. 2*2矩阵训练集比例对BP神经网络分类性能影响
  4. 程序员要学会读源代码
  5. VUE计算属性关键词: computed
  6. 删除sql下注册服务器
  7. Python __subclasses__() 函数获取类的所有子类
  8. javaScript设计模式之常用工厂模式
  9. target ajax,jQuery target - jquery事件
  10. 关于用户自定义控件与引用该控件的页面之间的javascript脚本冲突
  11. java导出excel超出65536条处理
  12. linux可执行文件bad interpreter解决方法
  13. 海思35xx移动侦测-修改sdk中sample到嵌入式设备测试成功
  14. win10和win11系统,手机或者其他设备连接不上电脑热点,一直在转圈圈的解决方法
  15. 重装系统后计算机无法联网,小编教你重装win10系统后电脑上不了网怎么办
  16. Log-normal distribution对数正态分布
  17. css样式属性值无效问题
  18. LANDESK8.8版本操作说明书之服务器安装
  19. 用proteus来玩二极管或门电路
  20. 国内外主流静态分析类工具汇总

热门文章

  1. 系统间数据传输,产品经理视角的9千字总结:接口、otter、log4j、SFTP、MQ……
  2. 四阶龙格库塔c语言,四阶龙格库塔算法的C语言实现
  3. server数据库与oracle,浅析Oracle和SQL Server-数据库专栏,ORACLE
  4. vs2015 html页面没有试图,vs2015 web设计视图假死,求帮助
  5. mysql select db error_select error:不能用DB-library(如isql)不能用DB-library(如isql
  6. datetime unix php,PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】...
  7. UEditor 任意文件上传漏洞
  8. linux 命令 抛后台,Linux 后台执行命令
  9. ExtJs的Reader
  10. flask总结之session,websocket,上下文管理