热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

爬虫进阶BeautifulSoup库

原标题:爬虫进阶-BeautifulSoup库爬虫进阶之路BeautifulSoup

原标题:爬虫进阶-Beautiful Soup 库


爬虫进阶之路



  • Beautiful Soup 简介

  • Beautiful Soup 安装

  • Beautiful Soup 库解析器

  • BeautifulSoup


    • 获取 title 节点,查看它的类型

    • 选择元素

    • 调用 name 属性获取节点的名称

    • 调用 attrs 获取所有属性

    • 简单获取属性的方式

    • 调用 string 属性获取节点元素包含的文本内容

    • 嵌套选择

    • 调用 children 属性,获取它的直接子节点

    • 调用 parent 属性,获取某个节点元素的父节点

    • 调用 parents 属性,获取某个节点元素的祖先节点

    • 调用 next_sibling 和 previous_sibling 分别获取节点的下一个和上一个兄弟元素


  • 方法选择器


    • find_all 方法传入 name 参数,根据节点名来查询元素

    • find_all 方法传入 attrs 参数,根据属性来查询

    • find_all 方法根据文本来查询

    • find 方法查询第一个匹配的元素


  • CSS 选择器




Beautiful Soup 简介


  • BeautifulSoup4 是一个 HTML/XML 的解析器,主要的功能是解析和提取 HTML/XML 的数据。和 lxml 库一样。


  • lxml 只会局部遍历,而 BeautifulSoup4 是基于 HTML DOM 的,会加载整个文档,解析 整个 DOM 树,因此内存开销比较大,性能比较低。


  • BeautifulSoup4 用来解析 HTML 比较简单,API 使用非常人性化,支持 CSS 选择器,是 Python 标准库中的 HTML 解析器,也支持 lxml 解析器。



Beautiful Soup 安装

目前,Beautiful Soup 的最新版本是 4.x 版本,之前的版本已经停止开发,这里推荐使用 pip 来安装,安装命令如下:

pip install beautifulsoup4

查看 Beautiful Soup 安装是否成功

from bs4 import BeautifulSoup
soup = BeautifulSoup('

Hello

','html.parser')
print(soup.p.string)

注意:
□ 这里虽然安装的是 beautifulsoup4 这个包,但是引入的时候却是 bs4,因为这个包源 代码本身的库文件名称就是bs4,所以安装完成后,这个库文件就被移入到本机 Python3 的 lib 库里,识别到的库文件就叫作 bs4。
□ 因此,包本身的名称和我们使用时导入包名称并不一定是一致的。



Beautiful Soup 库解析器

Beautiful Soup 在解析时实际上依赖解析器,它除了支持 Python 标准库中的 HTML 解析器外,还支持一些第三方解析器(比如 lxml)。下表列出了 Beautiful Soup 支持的解析器。
在这里插入图片描述
在这里插入图片描述
初始化 BeautifulSoup 使用 lxml,把第二个参数改为 lxml

from bs4 import BeautifulSoup
bs = BeautifulSoup('

Python

','lxml')
www.yii666.comprint(bs.p.string)


BeautifulSoup
  1. 基本用法

在这里插入图片描述


获取 title 节点,查看它的类型

from bs4 import BeautifulSoup
html = '''


The Dormouse's story


Once upon a time there were three little sisters; and their names were
,
Lacie and
Tillie;
and they lived at the bottom of a well.


...




'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
print(soup.prettify())
print(soup.title.string)

执行结果如下所示:

The Dormouse's story


  • 上述示例首先声明变量 html,它是一个 HTML 字符串。接着将它当作第一个参数传给 BeautifulSoup 对象,该对象的第二个参数为解析器的类型(这里使用 lxml),此时就完成了 BeaufulSoup 对象的初始化。

  • 接着调用 soup 的各个方法和属性解析这串 HTML 代码了。

  • 调用 prettify()方法。可以把要解析的字符串以标准的缩进格式输出。这里需要注意的是, 输出结果里面包含 body 和 html 节点,也就是说对于不标准的 HTML 字符串 BeautifulSoup, 可以自动更正格式。

  • 调用 soup.title.string,输出 HTML 中 title 节点的文本内容。所以,soup.title 可以选出 HTML 中的 title 节点,再调用 string 属性就可以得到里面的文本了。



选择元素

# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取head标签
print(soup.head)
# 获取p标签
print(soup.p)

运行结果

<head><title>The Dormouse's story</title></head>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>


  • 从上述示例运行结果可以看到,获取 head 节点的结果是节点加其内部的所有内容。

  • 最后,选择了 p 节点。不过这次情况比较特殊,我们发现结果是第一个 p 节点的内容,后面的几个 p 节点并没有选到。也就是说,当有多个节点时,这种选择方式只会选择到第一个匹配的节点,其他的文章来源站点https://www.yii666.com/后面节点都会忽略。



调用 name 属性www.yii666.com获取节点的名称

# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 调用 name 属性获取节点的名称
print(soup.title.name)

运行结果

title


调用 attrs 获取所有属性

# 调用 attrs 获取所有属性
print(soup.p.attrs)
print(soup.p.attrs['name'])

运行结果

{'class': ['title'], 'name': 'dromouse'}
dromouse

从上述运行结果可以看到,attrs 的返回结果是字典形式,它把选择节点的所有属性和属性值组合成一个字典。
如果要获取 name 属性,就相当于从字典中获取某个键值,只需要用中括号加属性名就可以了。例如,要获取 name 属性,就可以通过 attrs[‘name’] 来得到。


简单获取属性的方式

print(soup.p['name'])
print(soup.p['class'])

这里需要注意的是,获取属性有的返回结果是字符串,有的返回结果是字符串组成的列表。
比如,name 属性的值是唯一的,返回的结果就是单个字符串。而对于 class,一个节点元素可能有多个 class,所以返回的是列表


调用 string 属性获取节点元素包含的文本内容

print('调用 string 属性获取节点元素包含的文本内容')
print(soup.p.string)


嵌套选择

print('嵌套选择')
print(soup.head.title)
# 获取title的类型
print(type(soup.head.title))
# 获取标签内容
print(soup.head.title.string)

运行结果

<title>The Dormouse's story</title>
<class 'bs4.element.Tag'>
The Dormouse's story

从上述示例运行结果可以看到,调用 head 之后再次调用 title 可以选择 title 节点元素。 输出了它的类型可以看到,它仍然是 bs4.element.Tag 类型。也就是说,我们在 Tag 类型的基础上再次选择得到的依然还是 Tag 类型,每次返回的结果都相同。


调用 children 属性,获取它的直接子节点

from bs4 import BeautifulSoup
html = '''





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.


...


'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取孩子结点
print(soup.p.children)
# 遍历孩子结点
# 将列表中元素与下标枚举为元组
# 获取p标签下的孩子标签
for i, child in enumerate(soup.p.children):
print(i, child)

执行结果

<list_iterator object at 0x0CACF448>
0 Once upon a time there were three little sisters; and their names were
1 <a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>
2
3 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
4 and
5 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
6 and they lived at the bottom of a well.

从上述示例运行结果可以看到,调用 children 属性,返回结果是生成器类型。用 for 循环输出相应的内容。


调用 parent 属性,获取某个节点元素的父节点

from bs4 import BeautifulSoup
html = '''




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

Elsie

...


'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取父结点
print(soup.a.parent)

运行结果

<p class="story"> Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>
</p>

从上述示例运行结果可以看到,我们选择的是第一个 a 节点的父节点元素,它的父节点 是 p 节点,输出结果便是 p 节点及其内部的内容。 需要注意的是,这里输出的仅仅是 a 节点的直接父节点,而没有再向外寻找父节点的祖 先节点。如果想获取所有的祖先节点,可以调用 parents 属性。


调用 parents 属性,获取某个节点元素的祖先节点

from bs4 import BeautifulSoup
html = '''



Elsie


'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取父结点
print(type(soup.a.parents)) # 获取类型
print(list(enumerate(soup.a.parents)))

运行结果

[(0, <p class="story">
<a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>
</p>), (1, <body><p class="story">
<a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>
</p>
</body>), (2, <html>
<body><p文章来源地址41171.html class="story">
<a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>
</p>
</body></html>), (3, <html>
<body><p class="story">
<a class="sister" href="http://example.com/elsie" id="link1">
<span>Elsie</span>
</a>
</p>
</body></html>)]


调用 next_sibling 和 previous_sibling 分别获取节点的下一个和上一个兄弟元素

from bs4 import BeautifulSoup
html = '''


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

Elsie
Hello
Lacie and
文章来源地址41171.htmlhref="http://example.com/tillie" class="sister" id="link3">Tillie
and they lived at the bottom of a well.


'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取下一个结点的属性
print('Next Sibling', soup.a.next_sibling)
print('Previous Sibling', soup.a.previous_sibling)

运行结果

Next Sibling Hello
Previous Sibling Once upon a time there were three little sisters; and their names were


方法选择器

上面所讲的选择方法都是通过属性来选择的,这种方法非常快,但是如果进行比较复杂的选择的话,它就比较烦琐,不够灵活了。
Beautiful Soup 还提供了一些查询方法,例如:find_all()和 find()等。
find_all 是查询所有符合条件的元素。给它传入一些属性或文本,就可以得到符合条件的元素,它的功能十分强大。
语法格式如下:

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



find_all 方法传入 name 参数,根据节点名来查询元素

from bs4 import BeautifulSoup
html = '''



Hello





  • Foo

  • Bar

  • Jay



  • Foo

  • Bar




'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
for ul in soup.find_all(name='ul'):
print(ul.find_all(name='li'))
for li in ul.find_all(name='li'):
print(li.string)

结果如下

[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
Foo
Bar
Jay
[<li class="element">Foo</li>, <li class="element">Bar</li>]
Foo
Bar

从上述示例可以看到,调用 find_all()方法,name 参数值为 ul。返回结果是查询到的所有 ul 节点列表类型,长度为 2,每个元素依然都是 bs4.element.Tag 类型。因为都是 Tag 类型, 所以依然可以进行嵌套查询。再继续查询其内部的 li 节点,返回结果是 li 节点列表类型, 遍历列表中的每个 li,获取它的文本


find_all 方法传入 attrs 参数,根据属性来查询

from bs4 import BeautifulSoup
html = '''



Hello





  • Foo

  • Bar

  • Jay



  • Foo

  • Bar




'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all(attrs={'name': 'elements'}))

结果如下

[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
[<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]

从上述示例可以看到,传入 attrs 参数,参数的类型是字典类型。比如,要查询 id 为 list-1 的节点,可以传入 attrs={‘id’: ‘list-1’}的查询条件,得到的结果是列表形式,包含的内容就是符合 id 为 list-1 的所有节点。符合条件的元素个数是 1,长度为 1 的列表。
对于一些常用的属性,比如 id 和 class 等,可以不用 attrs 来传递。比如,要查询 id 为 list-1 的节点 ,可以直接传入 id 这个参数。示例如下:

print(soup.find_all(id='list-1'))
print(soup.find_all(class_='element'))

上述示例直接传入 id=’list-1’,就可以查询 id 为 list-1 的节点元素了。而对于 class 来 说,由于 class 在 Python 里是一个关键字,所以后面需要加一个下划线,即 class_=’element’, 返回的结果依然还是 Tag 组成的列表


find_all 方法根据文本来查询

find_all 方法传入 text 参数可用来匹配节点的文本,传入的形式可以是字符串,可以是正则表达式对象。

from bs4 import BeautifulSoup
import re
html = '''


'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(text=re.compile('link')))

运行结果

['Hello, this is a link', 'Hello, this is a link, too']

上述示例有两个 a 节点,其内部包含文本信息。这里在 find_all()方法中传入 text 参数, 该参数为正则表达式对象,结果返回所有匹配正则表达式的节点文本组成的列表。
除了 find_all()方法,还有 find()方法,不过后者返回的是单个元素,也就是第一个匹配的元素,而前者返回的是所有匹配的元素组成的列表


find 方法查询第一个匹配的元素

from bs4 import BeautifulSoup
import re
html = '''
<



Hello





  • Foo

  • Bar

  • Jay



  • Foo

  • Bar




'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取标签名为ul的标签体内容
print(soup.find(name='ul'))
# 获取返回结果的列表
print(type(soup.find(name='ul')))
# 查找标签中class是'list'
print(soup.find(class_='list'))

结果如下

<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<class 'bs4.element.Tag'>
<ul class="list" id="list-1">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>

上述示例使用 find 方法返回结果不再是列表形式,而是第一个匹配的节点元素,类型依然是 Tag 类型。


CSS 选择器

Beautiful Soup 还提供了另外一种选择器,那就是 CSS 选择器。使用 CSS 选择器时,只 需要调用 select()方法,传入相应的 CSS 选择器即可。

CSS相关知识



  • #element: id选择器

  • .element:类选择器


  • tag tag:
    派生选择器
    通过依据元素在其位置的上下文关系来定义样式,你可以使标记更加简洁。

from bs4 import BeautifulSoup
import re
html = '''



Hello





  • Foo

  • Bar

  • Jay



  • Foo

  • Bar




'''
# 获取bs4解析对象,使用解析器:lxml,html:解析内容
soup = BeautifulSoup(html, 'lxml')
# 获取class=panel标签下panel_heading,类选择器
print(soup.select('.panel .panel-heading'))
# 派生选择器
print(soup.select('ul li'))
# id选择器+类选择器
lis = soup.select('#list-2 .element')
for l in lis:
print('GET TEXT', l.get_text())
print('String:', l.string)

结果如下

[<div class="panel-heading">
<h4>Hello</h4>
</div>]
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
GET TEXT Foo
String: Foo
GET TEXT Bar
String: Bar

上述示例,用了 3 次 CSS 选择器,返回的结果均是符合 CSS 选择器的节点组成的列表。 例如,select(‘ul li’)则是选择所有 ul 节点下面的所有 li 节点,结果便是所有的 li 节点组成的列表。要获取文本,当然也可以用前面所讲的 string 属性。此外,还有一个方法,那就是 get_text()

该博文内容整合自尚学堂老师的PDF,感谢尚学堂的教学资源,感谢努力,感谢技术开源,知识共享。
一起加油!!!

来源于:爬虫进阶-Beautiful Soup 库


推荐阅读
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 【爬虫】关于企业信用信息公示系统加速乐最新反爬虫机制
    ( ̄▽ ̄)~又得半夜修仙了,作为一个爬虫小白,花了3天时间写好的程序,才跑了一个月目标网站就更新了,是有点悲催,还是要只有一天的时间重构。升级后网站的层次结构并没有太多变化,表面上 ... [详细]
  • Yii framwork 应用小窍门
    Yiiframework应用小窍门1.YiiFramework]如何获取当前controller的名称?下面语句就可以获取当前控制器的名称了!Php代码 ... [详细]
  • yii2 绑定框架事件
    后端开发|php教程php,yii2后端开发-php教程我想要添加自定义代码处理yii2框架的Application::EVENT_BEFORE_REQUEST时触发的事件,但是不 ... [详细]
  • java线条处理技术_Java使用GUI绘制线条的示例
    在Java的GUI编程中,如何使用GUI绘制线条?以下示例演示了如何使用Graphics2D类的Line2D对象的draw()方法作为参数来绘制一条线。 ... [详细]
  • java.lang.Class.getDeclaredMethod()方法java.lang.Class.getDeclaredMethod()方法用法实例教程-方法返回一个Met ... [详细]
  • 原标题:Python中numpy.power()函数介绍Python中numpy.power()函数介绍power(x,y)函数, ... [详细]
  • 本文详细介绍了PHP中与URL处理相关的三个函数:http_build_query、parse_str和查询字符串的解析。通过示例和语法说明,讲解了这些函数的使用方法和作用,帮助读者更好地理解和应用。 ... [详细]
  • SOAR系统
    SOAR系统 ... [详细]
author-avatar
sueann88314_254
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有