BeautifulSoup总结
介绍
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)
结果如下:
为什么会返回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())
返回结果如下: