前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据获取:​网页解析之BeautifulSoup

数据获取:​网页解析之BeautifulSoup

作者头像
马拉松程序员
发布2023-09-02 08:03:41
1820
发布2023-09-02 08:03:41
举报

在上一节中,认识了Python中的lxml库,可以通过XPath来寻找页面中的位置,这也是仅仅对于结构完整的页面,但是对于有针对性的获取内容的时候并不很友好,比如说链接中以XXX开头或者结尾,而且中间符合某些特定规则,所以这时候需要认识一个新朋友,那就是另外一个很强大的解析库——Beautiful Soup。

与 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,通过解析文档为用户提供需要抓取的数据的功能。

安装BeautifulSoup

Beautiful Soup也有很多版本,不过Beautiful Soup3已经停止更新了,目前最新的都是Beautiful Soup4,而且也已经移植到bs4库中,我们安装bs4库后就可以直接使用。安装库使用pip安装,安装命令:

代码语言:javascript
复制
pip install beautifulsoup4

安装解析器

Beautiful Soup中支持的解析器有很多种,不仅仅支持Python标准库中的HTML解析器,还可以使用一些第三方的解析器,比如说lxml等,如表所示,是几种常见的解析器的优缺点。

解析器

使用方式

优点

缺点

Python标准库

BeautifulSoup(html, "html.parser")

Python的内置标准库、文档容错性较强

执行速度适中

lxml解析器

BeautifulSoup(html, "lxml")

速度快、文档容错性较强

依赖C语言库

html5lib

BeautifulSoup(html, "html5lib")

以浏览器的方式解析文档、容错性最好

执行速度慢

一般情况下可以使用Python标准库或者lxml作为常用的解析器,对于爬虫来说,比起速度来说,准确性的要求并不是很高。如果在解析文档上花费的时间太多,必然会导致爬虫的效率低。

Python标准库解析器并不需要安装,因为本身自带的,lxml解析器在上一节使用它作为解析器时候已经安装过了,也不需要额外安装,直接使用即可。html5lib的安装跟BeautifulSoup一样,使用pip安装:

代码语言:javascript
复制
pip install html5lib

生成解析对象

代码语言:javascript
复制
from bs4 import BeautifulSoup
from lxml import etree
text = '''
<html>
<head>
<title>实例HTML</title>
</head>
<body>
<div>
<h1>这是标题</h1>
</div>
<div>
<ul>
<li class="c1"><a href="link1.html" title="链接1">第一个链接</a></li>
<li class="c2"><a href="link2.html" title="链接2">第二个链接</a></li>
<li class="c3"><a href="link3.html" title="链接3">第三个链接</a></li>
</ul>
</div>
</body>
</html>
'''
# 生成一个BeautifulSoup对象
soup = BeautifulSoup(text, 'html.parser')
# 对象类型
print(type(soup))
#代码结果:
<class 'bs4.BeautifulSoup'>

现在就获得了一个BeautifulSoup的对象,Beautiful Soup其实是将HTML文档转换成一个复杂的树形结构,每个节点都是Python中的对象,所有对象可以归纳为 4 种:Tag、NavigableString、BeautifulSoup、Comment,后两种根本上讲也是前面两种的特殊情况。下面我们简要讲解这几个对象。

Tag

Tag是最容易理解的,跟字面意思一样,就是HTML中的标签。比如:一个a标签就是一个对象:

代码语言:javascript
复制
<a href="link1.html" title="链接1">第一个链接</a>

在tag对象中比较重要的两个属性name和attrs。通过这两个属性可以获取到标签中的信息:

代码语言:javascript
复制
print(soup.a.name)
print(soup.a.attrs)
#代码结果:
a
{'href': 'link1.html', 'title': '链接1'}

name其实就是获取标签的名称,这个是使用的不多,毕竟在日常使用的时候都会知道需要找哪些标签中的内容。attrs获取是标签中的属性,结果是一个字典类型的集合。

NavigableString

在上面两个属性中,并没法获取标签中的内容,那么NavigableString就是用来获取标签中文本内容的,用法也比较简单,直接使用string即可。

代码语言:javascript
复制
print(soup.a.string)
print(type(soup.a.string))
#代码结果:
第一个链接
<class 'bs4.element.NavigableString'>

BeautifulSoup

这个对象在前面提到过,表示一个页面(文档)的内容,可以作为一个特殊的Tag。

代码语言:javascript
复制
print(type(soup))
#代码结果:
<class 'bs4.BeautifulSoup'>

Comment

Comment对象也是一个特殊的NavigableString,读取的内容是注释里面的内容。把上面示例中的第一个a标签的内容更改成如下:

代码语言:javascript
复制
<a href="link1.html" title="链接1"><!--Hello--></a>
print(soup.a.string)
print(type(soup.a.string))
#代码结果:
Hello
<class 'bs4.element.Comment'>

注意:如果在标签内的文本既有正常文字也有注释,这时候string属性就无法获取到内容:

代码语言:javascript
复制
<a href="link1.html" title="链接1">第一个链接<!--Hello--></a>
print(soup.a.string)
#代码结果:
None

获取文本内容可以使用text方法,虽然text和string结果都是字符串,但是两个对象其实并不相同。

代码语言:javascript
复制
<a href="link1.html" title="链接1">第一个链接<!--Hello--></a>
print(soup.a.text)
print(type(soup.a.text))
#代码结果:
第一个链接
<class 'str'>

搜索文档树

把HTML内容解析成为一个BeautifulSoup对象后,对这个对象的操作才是BeautifulSoup这个模块所能体验的强大之处。本身BeautifulSoup本身有着丰富的节点遍历功能,包括父节点、子节点、子孙节点的获取和逐个元素的遍历。

不过在实际应用上,我们使用遍历的还是少数,使用搜索的还是多数,现在很多网页中的元素很丰富,我们很少会把一个页面中的所有内容都获取下来,基本是需要的重点内容,这对于遍历来说,搜索更加显得便捷实用。

find_all()

说到搜索,最常使用的肯定是BeautifulSoup的find_all()方法,它会搜索当前 tag 的所有 tag 子孙节点,并判断每个节点是否符合过滤器的条件。

find_all()方法的完整参数为find_all(name, attrs, recursive, text,limit, **kwargs):

name:标签名称的过滤,支持正则

attrs:标签的属性条件的过滤,支持正则;

recursive:bool选项,如果为True,find_all()将遍历所有节点,否则只有子节点,默认为True;

text:标签中的文本过滤,;

limit:搜索限制过滤,如果不为空,表示找到指定数量的元素后将停止搜索,默认为空,将搜索全部;

kwargs:表示可以添加多个属性值参数过滤。

1.name参数

搜索所有a标签

代码语言:javascript
复制
links = soup.find_all('a')
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>, <a href="link3.html" title="链接3">第三个链接</a>]

搜索所有名字带“a”标签

代码语言:javascript
复制
links = soup.find_all(re.compile(".*a.*"))
print(links)

代码结果(head和a标签都符合)

代码语言:javascript
复制
[<head>
<title>实例HTML</title>
</head>, <a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>, <a href="link3.html" title="链接3">第三个链接</a>]

2. arrts参数

搜索所有a标签中title值为“链接1”

代码语言:javascript
复制
links = soup.find_all('a', attrs={"title": "链接1"})
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link1.html" title="链接1">第一个链接</a>]

3. kwargs参数:

搜索所有a标签中herf中带“1”的标签

代码语言:javascript
复制
links = soup.find_all('a', href=re.compile(".*1.*"))
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link1.html" title="链接1">第一个链接</a>]

4. text参数:

#搜索所有a标签中,文本带“二”的标签

代码语言:javascript
复制
links = soup.find_all('a', text=re.compile(".*二.*"))
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link2.html" title="链接2">第二个链接</a>]

如果不加a标签,搜索的内容则仅仅是文本。

#搜索所有a标签中,文本带“二”的标签

代码语言:javascript
复制
links = soup.find_all('text=re.compile(".*二.*"))
print(links)

代码结果:

代码语言:javascript
复制
['第二个链接']

5. limit参数

#搜索所有a标签中,超链接以link开头,最多2个

代码语言:javascript
复制
links = soup.find_all('a', href=re.compile("link.*"), limit=2)
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>]

find()

find()方法相当于给find_all()方法默认添加limit=1,仅仅发挥符合条件的第一个Tag。方便有时候我们仅仅需要一个值的时候,直接可以调用。参数跟find_all()一样,用法也是相同。

CSS选择器

Beautiful Soup中用select()方法来CSS样式的进行筛选,当然也可以筛选标签。在标签的属性中,class的属性就是当前标签的CSS样式,返回的结果同样也是list。

1.通过标签名查找

查找所有a标签

代码语言:javascript
复制
links = soup.select('a')
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link1.html" title="链接1">第一个链接</a>, <a href="link2.html" title="链接2">第二个链接</a>]

2.通过CSS样式类名查找

查找样式类名为c1的标签

代码语言:javascript
复制
links = soup.select('.c1')
print(links)

代码结果:

代码语言:javascript
复制
[<li class="c1"><a href="link1.html" title="链接1">第一个链接</a></li>]

3.通过标签属性查找

查找属性中href="link1.html"的a标签

代码语言:javascript
复制
links = soup.select('a[href="link1.html"]')
print(links)

代码结果:

代码语言:javascript
复制
[<a href="link1.html" title="链接1">第一个链接</a>]

在标签+属性组合中,属性不支持正则表达式。

4.获取查找到的内容

除了以上集中还可以使用标签的id等元素来进行查找,但是不管使用哪种方式,最终的是回去标签的内容或者属性中的值,那么找到相应的标签后,怎么取值呢?如果是去标签属性值,跟使用字典取值方式一样。如果是获取标签的文本,直接使用get_text()方法,可以获取到标签的文本内容。

查找属性中href="link1.html"的a标签

代码语言:javascript
复制
links = soup.select('a[href="link1.html"]')
#打印标签中的超链接值
print(links[0][‘href])
#打印标签文本内容
print(links[0].get_text())

代码结果:

代码语言:javascript
复制
第一个链接
link1.html

不管是使用lxml还是Beautiful Soup,多数结果都是获取文本内容或者是标签的属性值。文本内容多数是需要获取的内容,整理下来放到list中,最后可能保存本地文件或者数据库,而标签的中属性值多数可以找到子链接(详情链接),知道了怎么定位和获取页面的元素,下面我们就可以动手爬取页面的内容了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 马拉松程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 在上一节中,认识了Python中的lxml库,可以通过XPath来寻找页面中的位置,这也是仅仅对于结构完整的页面,但是对于有针对性的获取内容的时候并不很友好,比如说链接中以XXX开头或者结尾,而且中间符合某些特定规则,所以这时候需要认识一个新朋友,那就是另外一个很强大的解析库——Beautiful Soup。
  • 与 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,通过解析文档为用户提供需要抓取的数据的功能。
    • 安装BeautifulSoup
      • 安装解析器
        • 生成解析对象
          • 搜索文档树
            • CSS选择器
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档