经过了前面几篇文章的学习,估计你已经会爬不少中小型网站了。但是有人说,前面的正则很难唉,学不好。正则的确很难,有人说过:如果一个问题用正则解决,那么就变成了两个问题。所以说学不会是很正常的,不怕,除了正则,我们还可以用另外一个强大的库来解析html。所以,今天的主题就是来学习这个强大的库--BeautifulSoup,不过正则还是需要多多练习下的。
因为是第三方库所以我们需要下载,在命令行敲下以下代码进行下载
pip install beautifulsoup4
安装第三方解析库
pip install lxml
pip install html5lib
如果不知道有什么用请往下看
1.相关解析库的介绍
这里官方推荐解析库为lxml,因为它的效率高。下面都是用lxml解析库来进行解析的。
2.详细语法介绍
本文是进行解析豆瓣图书首页https://book.douban.com/
1)创建bs对象
from bs4 import BeautifulSoup
import requests
response = requests.get('https://book.douban.com/').text
# print(response)
# 创建bs对象
soup = BeautifulSoup(response, 'lxml') # 使用到了lxml解析库
2)获取相关标签
标签:
上面的a就是一个标签名字,最简单的就是这样,可以简单理解为<>里面的第一个单词就是标签名
# 获取标签
print(soup.li) # 这个只是获取第一个li标签
# 结果
3)获取标签的名字和内容
标签的名字和内容:
豆瓣
如上面所说,a就是标签名字,而两个标签之中所夹杂的内容就是我们所说的内容,如上,豆瓣就是该标签的内容
# 获取标签名字
print(soup.li.name)
# 获取标签内容
print(soup.li.string) # 这个只能是这个标签没有子标签才能正确获取,否则会返回None
# 结果
li
None
由于这个li标签里面还有个子标签,所以它的文本内容为None
下面这个就可以获取它的文本内容
# 获取标签内的标签
print(soup.li.a)
print(soup.li.a.string) # 这个标签没有子标签所以可以获取到内容
# 结果
豆瓣
4)获取标签属性,有两种方法
标签属性:
可以简单理解为属性就是在标签名字旁边而且在前一个<>符号里面的,还有是有等号来进行体现的。所以上面的href就是标签属性名字,等号右边的就是属性的值,上面的值是个网址
# 获取标签属性
print(soup.li.a['href']) # 第一种
print(soup.li.a.attrs['href']) # 第二种
# 结果
https://www.douban.com
https://www.douban.com
5)获取标签内的子标签
子标签:
豆瓣比如我们现在获取的li标签,所以a标签就是li标签的子标签
# 获取标签内的标签
print(soup.li.a)
# 结果
6)获取所有子节点
子节点:这个和子标签是差不多的,只不过这里是获取一个标签下的所有子标签,上面的只是获取最接近该标签的子标签
# 获取子节点
print(soup.div.contents) # 返回一个列表 第一种方法
for n, tag in enumerate(soup.div.contents):
print(n, tag)
# 结果
['\n',
...
0
1
...
这个是获取div下的所有子节点,.content就是获取子节点的属性
7)第二种方法获取所有子节点
# 第二种方法
print(soup.div.children) # 返回的是一个迭代器
for n, tag in enumerate(soup.div.children):
print(n, tag)
这个是用.children获取所有的子节点,这个方法返回的是一个迭代器
8)获取标签的子孙节点,就是所有后代
子孙节点:
豆瓣
从上面知道,li标签是ul标签的子标签,a标签是li标签的子标签,若此时我们获取的是ul标签,所以li标签和a标签都是ul标签的子孙节点
# 获取标签的子孙节点
print(soup.div.descendants) # 返回的是一个迭代器
for n, tag in enumerate(soup.div.descendants):
print(n, tag)
# 结果
...
0
1
...
这里用到了.descendants属性,获取的是div标签的子孙节点,而且返回结果是一个迭代器
9)获取父节点和所有祖先节点
既然有了子节点和子孙节点,反过来也是有父节点和祖先节点的,所以都很容易理解的
# 获取父节点
print(soup.li.parent) # 返回整个父节点
# 获取祖先节点
print(soup.li.parents) # 返回的是一个生成器
for n, tag in enumerate(soup.li.parents):
print(n, tag)
.parent属性是获取父节点,返回来的是整个父节点,里面包含该子节点。.parents就是获取所有的祖先节点,返回的是一个生成器
10)获取兄弟节点
兄弟节点:
豆瓣1
豆瓣2
豆瓣3
比如上面的html代码,里面的li标签都是ul标签的子节点,而li标签都是处于同级的,所以上面的li标签都是各自的兄弟。这就是兄弟节点。
# 获取兄弟节点
print(soup.li.next_siblings) # 获取该标签的所有同级节点,不包括本身 返回的是一个生成器
for x in soup.li.next_siblings:
print(x)
# 结果
...
.next_siblings属性是获取该标签的所有在他后面的兄弟节点,不包括他本身。同时返回结果也是一个迭代器
同理,既然有获取他的下一个所有兄弟标签,也有获取他前面的所有兄弟标签
soup.li.previous_siblings
如果只是获取一个即可,可以选择把上面的属性后面的s字母去掉即可,如下
soup.li.previous_sibling # 获取前一个兄弟节点
soup.li.next_sibling # 获取后一个兄弟节点
3.bs库的更高级的用法
在前面我们可以获取标签的名字、属性、内容和所有的祖孙标签。但是当我们需要获取任意一个指定属性的标签还是有点困难的,所以,此时有了下面这个方法:
soup.find_all( name , attrs , recursive , text , **kwargs )
name:需要获取的标签名
attrs:接收一个字典,为属性的键值,或者直接用关键字参数来替代也可以,下面
recursive:设置是否搜索直接子节点
text:对应的字符串内容
limit:设置搜索的数量
1)先使用name参数来进行搜索
# 先使用name参数
print(soup.find_all('li')) # 返回一个列表,所有的li标签名字
# 结果
[
,...
这里获取了所有标签名字为li的标签
2)使用name和attrs参数
# 使用name和attrs参数
print(soup.find_all('div', {'class': 'more-meta'})) # 这个对上个进行了筛选,属性参数填的是一个字典类型的
# 结果
[