介绍

BeautifulSoup是在爬虫领域常用的一个解析库,这里主要对BeautifulSoup的基本使用做一个总结,默认已经安装了python

安装bs4和lxml

安装bs4

pip install bs4

安装lxml

pip install lxml

BeautifulSoup的解析器

BeautifulSoup共有四种解析器,下面对这四种解析器进行对比:

1.html.parser:这个解析器是Python内置的标准库,解析速度一般,文档容错能力强,使用方法如下:

2.lxml:lxml解析器解析速度很快,文档容错能力强

3.xml:速度快,唯一支持xml的解析器

4.html5lib:容错性在这四个当中最好,以浏览器的方式解析文档,但是速度慢

解析器的使用方法,这里使用lxml作为例子:

soup = BeautifulSoup(html, 'lxml')

基本使用

创建BeautifulSoup对象:

from bs4 import BeautifulSoup

html = '''
<html>
    <head>
        <title>This is title.</title
    </head>
    <body>
        <div class="box container" id="mydiv">
            I am a boy.
            <p>Hello World.</p>
            <p>Hello BeautifulSoup.</p>
        </div>
    </body>
</html>
'''
soup = BeautifulSoup(html, 'lxml')
print(soup.prettify())

这里首先给出一段html,然后使用BeautifulSoup()来创建一个对象,prettify()方法会将html以标准的缩进格式输出到控制台。

节点选择器

使用上面的html为例子,获取title节点:

print(soup.title)  # 输出为:<title>This is title.</title>

如果想要获取title节点中的文字,可以使用string属性来获取:

print(soup.title.string)  # 输出为:This is title.

那是不是可以使用同样的方式来获取div中I am a boy这几个字呢?我们来试一试:

print(soup.div.string)

结果如下:
image
为什么会返回None呢?因为div节点内部不仅仅包含文字节点,还有子节点p节点,通过string属性不能够获取它的直接文本节点。

所以可以得知string属性的用法:如果一个节点内部不包含其他元素节点,则可以通过string属性来获取它的文本,如果有就不能获取到文本。

那如何来解决这种情况呢?
可以通过contents属性来获取到某个节点所有直接子节点,包括元素节点、属性节点和文本节点,这样我们就能得到上面我们想要的得到的内容了:

print(soup.div.contents)

来看一下此时的返回结果:
在这里插入图片描述
可以看到,contents属性返回了div节点下的所有直接子节点组成的列表!其中第一个元素就是我们想要的内容。

如果想要获取直接子节点,除了contents属性外,还有children属性也可以获取直接子节点,不过children返回的是一个iterator,也就是迭代器,需要通过for循环来遍历以得到结果。

print(soup.div.children)
print('*'*40)
for child in soup.div.children:
    print(child)

结果如下图:
在这里插入图片描述
可以看到children属性返回的确实是一个iterator,我们通过for循环得到了div节点的三个直接子节点。

说完了直接子节点的获取,再来看看使用descendants属性获取所有的子孙节点:

print(soup.body.descendants)
print('*'*40)
for child in soup.body.descendants:
    print(child)

结果如下:
在这里插入图片描述
可以看到,descendants属性返回的是一个generator,我们通过for循环输出值,在图中,我们看到它先输出了div节点,再通过div节点输出里面的p节点,再通过p节点输出p节点的文本节点,这就输出了所有的子孙节点。

说完子孙节点,再来看看父节点的获取。

通过parent属性获取某个节点的直接父节点:

print(soup.title.parent)

结果如下:
在这里插入图片描述

还可以通过parents属性来获取某个节点的所有父节点,返回一个生成器:

print(soup.p.parents)
for parent in soup.p.parents:
	print(parent)

通过previous_sibling和next_sibling获取节点的前一个兄弟节点和后一个兄弟节点:

print(soup.p.preivous_sibling)
print(soup.p.next_sibling)
# 通过previous_siblings获取节点的前面的所有兄弟节点,返回生成器
print(soup.p.previous_siblings)
# 通过next_siblings获取节点的后面的所有兄弟节点,返回生成器
print(soup.next_siblings)

获取属性可以使用attrs来获取:

print(soup.div.attrs)  # 返回一个字典,里面是所有属性和属性值的键值对
print(soup.div.attrs["class"])  # 获取class属性的值

注意:如果属性有多个值,比如class="box container"这种,使用attrs[“class”]会获取到一个列表。

方法选择器

BeautifulSoup有两个常用的方法:find_all()和find()方法

来看find_all()的API:

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

通过name属性来查询,例如:查找所有name为div的元素:

print(soup.find_all(name="div"))

结果如图:
在这里插入图片描述
可以看到使用find_all()方法返回了所有name为div的元素组成的列表。

通过attrs属性进行查找,例如:查找所有id为mydiv的元素:

print(soup.find_all(attrs={"id": "mydiv"}))

结果如图:
在这里插入图片描述

这里如果属性是id或者class可以有个简单的写法:

print(soup.find_all(id="mydiv"))
# class和关键字冲突,所以可以使用class_来表示
print(soup.find_all(class_="box"))

find方法和find_all()方法类似,只不过find()方法返回查询到的第一个元素,而find_all()返回查询到的所有元素。

CSS选择器

使用css选择器只需要调用select()方法并传入相应的css选择器即可,例如:

print(soup.select("div p"))  # 获取div节点下的所有p节点

获取文本除了上面的string属性外,还可以使用get_text()方法:

for p in soup.select("div p"):
    print(p.get_text())

返回结果如下:
在这里插入图片描述

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐