社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

python爬虫常用库之BeautifulSoup详解

sergiojune • 8 年前 • 837 次点击  

python爬虫常用库之BeautifulSoup详解

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

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


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

pip install beautifulsoup4

安装第三方解析库

pip install lxml

pip install html5lib

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

1.相关解析库的介绍


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

2.详细语法介绍

本文是进行解析豆瓣图书首页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 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属性有点不一样哈,这里的他会获取该标签的所有文本内容,不管有没有子标签

写在最后

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

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

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

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

MORE
延伸阅读

◐◑爬取《The Hitchhiker’s Guide to Python!》python进阶书并制成pdf

◐◑ python爬虫常用库之requests详解

◐◑ 老司机带你用python来爬取妹子图



日常学python

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



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/cEdebxwmxu
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/9744