博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python爬虫常用库之BeautifulSoup详解
阅读量:5873 次
发布时间:2019-06-19

本文共 5981 字,大约阅读时间需要 19 分钟。

这是日常学python的第16篇原创文章

经过了前面几篇文章的学习,估计你已经会爬不少中小型网站了。但是有人说,前面的正则很难唉,学不好。正则的确很难,有人说过:如果一个问题用正则解决,那么就变成了两个问题。所以说学不会是很正常的,不怕,除了正则,我们还可以用另外一个强大的库来解析html。所以,今天的主题就是来学习这个强大的库--BeautifulSoup,不过正则还是需要多多练习下的。

因为是第三方库所以我们需要下载,在命令行敲下以下代码进行下载

 

pip install beautifulsoup4

安装第三方解析库

 

pip install lxml

 

pip install html5lib

如果不知道有什么用请往下看

1.相关解析库的介绍

这里官方推荐解析库为lxml,因为它的效率高。下面都是用lxml解析库来进行解析的。

2.详细语法介绍

本文是进行解析豆瓣图书首页

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 data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>

上面的a就是一个标签名字,最简单的就是<a></a>这样,可以简单理解为<>里面的第一个单词就是标签名

 

# 获取标签

print(soup.li)  # 这个只是获取第一个li标签
# 结果
<li class="">
<a data-moreurl-dict='{"from":
"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
</li>

3)获取标签的名字和内容

标签的名字和内容:

 

<a >豆瓣</a>

如上面所说,a就是标签名字,而两个标签之中所夹杂的内容就是我们所说的内容,如上,豆瓣就是该标签的内容

 

# 获取标签名字

print(soup.li.name)
# 获取标签内容
print(soup.li.string)  # 这个只能是这个标签没有子标签才能正确获取,否则会返回None
# 结果
li
None

由于这个li标签里面还有个子标签,所以它的文本内容为None

下面这个就可以获取它的文本内容

 

# 获取标签内的标签

print(soup.li.a)
print(soup.li.a.string)  # 这个标签没有子标签所以可以获取到内容
# 结果
<a data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
豆瓣

4)获取标签属性,有两种方法

标签属性:

 

<a href="https://www.douban.com" target="_blank">豆瓣</a>

可以简单理解为属性就是在标签名字旁边而且在前一个<>符号里面的,还有是有等号来进行体现的。所以上面的href就是标签属性名字,等号右边的就是属性的值,上面的值是个网址

 

# 获取标签属性

print(soup.li.a['href'])  # 第一种
print(soup.li.a.attrs['href'])  # 第二种
# 结果
https://www.douban.com
https://www.douban.com

5)获取标签内的子标签

子标签:

 

<li><a>豆瓣</a></li>

比如我们现在获取的li标签,所以a标签就是li标签子标签

 

# 获取标签内的标签

print(soup.li.a)
# 结果
<a data-moreurl-dict='{"from":"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>

6)获取所有子节点

子节点:这个和子标签是差不多的,只不过这里是获取一个标签下的所有子标签,上面的只是获取最接近该标签的子标签

 

# 获取子节点

print(soup.div.contents)  # 返回一个列表 第一种方法
for n, tag in enumerate(soup.div.contents):
   print(n, tag)
# 结果
['\n', <div class="bd">
<div class="top-nav-info">
<a class="nav-login" href="https:
//www.douban.com/accounts/login?source=book" rel="nofollow">登录</a>
...
0
1 <div class="
bd">
<div class="
top-nav-info">
...

这个是获取div下的所有子节点,.content就是获取子节点的属性

7)第二种方法获取所有子节点

 

# 第二种方法

print(soup.div.children)  # 返回的是一个迭代器
for n, tag in enumerate(soup.div.children):
   print(n, tag)

这个是用.children获取所有的子节点,这个方法返回的是一个迭代器

8)获取标签的子孙节点,就是所有后代

子孙节点:

 

<ul>

<li>
<a>豆瓣</a>
</li>
</ul>

从上面知道,li标签ul标签子标签a标签li标签子标签,若此时我们获取的是ul标签,所以li标签和a标签都是ul标签的子孙节点

 

# 获取标签的子孙节点

print(soup.div.descendants)  # 返回的是一个迭代器
for n, tag in enumerate(soup.div.descendants):
   print(n, tag)
# 结果
...
<generator object descendants at 0x00000212C1A1E308>
0
1 <div class="bd">
<div class="top-nav-info">
<a class="nav-login" href="https:
//www.douban.com/accounts/login?source=book" rel="nofollow">登录</a>
...

这里用到了.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)获取兄弟节点

兄弟节点:

 

<ul>

<li>
<a>豆瓣1</a>
</li>
<li>
<a>豆瓣2</a>
</li>
<li>
<a>豆瓣3</a>
</li>
</ul>

比如上面的html代码,里面的li标签都是ul标签的子节点,而li标签都是处于同级的,所以上面的li标签都是各自的兄弟。这就是兄弟节点。

 

# 获取兄弟节点

print(soup.li.next_siblings)  # 获取该标签的所有同级节点,不包括本身  返回的是一个生成器
for x in soup.li.next_siblings:
   print(x)
# 结果
<generator object next_siblings at 0x000002A04501F308>
<li class="on">
<a data-moreurl-dict='{"from":
"top-nav-click-book","uid":"0"}' href="https://book.douban.com">读书</a>
</li>
...

.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 class="">
<a data-moreurl-dict='{"from":
"top-nav-click-main","uid":"0"}' href="https://www.douban.com" target="_blank">豆瓣</a>
</li>, <li class="on">
...

这里获取了所有标签名字为li的标签

2)使用name和attrs参数

 

# 使用name和attrs参数

print(soup.find_all('div', {
'class': 'more-meta'}))  # 这个对上个进行了筛选,属性参数填的是一个字典类型的
# 结果
[<div class="more-meta">
<h4 class="title">
                 刺
               </h4>
...

这里搜索了具有属性为class='more-meta'的div标签

3)根据关键字参数来搜索

 

# 对相关属性进行进行查找也可以这样

print(soup.find_all(class_='more-meta'))  # 使用关键字参数,因为class是python关键字,所以关键字参数时需要加多一个下划线来进行区别
# 结果
和上面的结果一样
...

这里注意,我们找的是class属性为more-meta的标签,用了关键字参数,但是python里面有class关键字,所以为了不使语法出错,所以需要在class加个下划线

其他参数的就不再介绍了,可以自行去官网查看

4)find()方法

此方法与find_all()方法一样,只不过这个方法只是查找一个标签而已,后者是查找所有符合条件的标签。

还有很多类似的方法,用法都差不多,就不再一一演示了,需要的可以去官网查看

5)select()方法

这个方法是使用css选择器来进行筛选标签的。

css选择器:就是根据标签的名字,id和class属性来选择标签。

  • 通过标签名:直接写该标签名,如 li a  ,这个就是找li标签下的a标签

  • 通过class属性:用. 符号加class属性值,如 .title .time 这个就是找class值为title下的class值为time的标签

  • 通过id属性:用# 加id属性值来进行查找,如 #img #width 这个就是找id值为img下的id值为width的标签

  • 上面三者可以混合使用,如 ul .title #width

如果还不太会的话,可以直接在浏览器上按下f12来查看

位置在箭头所指的位置就是选择器的表达

代码如下

 

# 还可以用标签选择器来进行筛选元素, 返回的都是一个列表

print(soup.select('ul li div'))  # 这个是根据标签名进行筛选
print(soup.select('.info .title'))  # 这个是根据class来进行筛选
print(soup.select('#footer #icp'))  # 这个是根据id来进行筛选
# 上面的可以进行混合使用
print(soup.select('ul li .cover a img'))

这里的获取属性和文本内容

 

# 获取属性

for attr in soup.select('ul li .cover a img'):
   # print(attr.attrs['alt'])
   # 也可以这样
   print(attr['alt'])
# 获取标签的内容
for tag in soup.select('li'):
   print(tag.get_text())  # 里面可以包含子标签,会将子标签的内容连同输出

.get_tex()方法和前面的.string属性有点不一样哈,这里的他会获取该标签的所有文本内容,不管有没有子标签

写在最后

以上的这些都是个人在学习过程中做的一点笔记。还有点不足,如果有错误的话欢迎大佬指出哈。如果想要查看更多相关用法可以去官方文档查看:

学习参考资料:https://edu.hellobi.com/course/157

如果这篇文章对你有用,点个赞,转个发如何?

还有,祝大家今天愚人节快乐

MORE延伸阅读

◐◑

◐◑ 

◐◑ 

日常学python

代码不止bug,还有美和乐趣

转载地址:http://ivhnx.baihongyu.com/

你可能感兴趣的文章
ABP源码分析四十:ZERO的Application和Tenant
查看>>
[论文]Clustering-Based Ensembles as an Alternative to Stacking
查看>>
SVN clean失败解决方法
查看>>
正则判断手机号是不是11位
查看>>
清浮动,防止上下margin重叠(浏览器顶部空白崩溃)
查看>>
2018年终总结
查看>>
StringBuffer与StringBuilder
查看>>
同步、异步、阻塞、非阻塞 简析
查看>>
PYthon常用模块 logging 日志
查看>>
BZOJ1257:[CQOI2007]余数之和(整除分块)
查看>>
[Android]HttpPost之post请求传递Json数据
查看>>
在View页面,使用@if(){ }输出判断正确的内容
查看>>
js或jquery如何获取父级、子级、兄弟元素(包括祖级、孙级等)
查看>>
软件测试为什么需要学习Linux的知识?Linux学到什么程度?-log5
查看>>
amazon中文文档
查看>>
CodeVs 1017 乘积最大(DP)
查看>>
智能运维基础设施
查看>>
01.LoT.UI 前后台通用框架分解系列之——小图片背景全屏显示(可自动切换背景)...
查看>>
[BZOJ] 3301: [USACO2011 Feb] Cow Line
查看>>
KNN K近邻算法
查看>>