乐趣区

关于SegmentFault:爬虫系列-6详解爬虫中BeautifulSoup4的用法

bs4,全称 BeautifulSoup 4,它是 Python 独有的一种解析形式。也就是说只有 Python 语言才能够通过这种形式去解析数据。

BeautifulSoup 3 只反对 Python2,所以曾经被淘汰了。

官网的介绍是这样的

Beautiful Soup 提供一些简略的、python 式的函数用来解决导航、搜寻、批改分析树等性能。它是一个工具箱,通过解析文档为用户提供须要抓取的数据,因为简略,所以不须要多少代码就能够写出一个残缺的应用程序。Beautiful Soup 主动将输出文档转换为 Unicode 编码,输入文档转换为 utf-8 编码。你不须要思考编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup 就不能自动识别编码方式了。而后,你仅仅须要阐明一下原始编码方式就能够了。Beautiful Soup 已成为和 lxml、html6lib 一样杰出的 python 解释器,为用户灵便地提供不同的解析策略或强劲的速度。

看起来很简单,我用本人的了解,艰深的解释一下

咱们晓得一个网页的源代码,是由多个标签组成,比方 <html>、<div>、<td>、<span> 等等组成的,而 bs4 就是用来帮咱们精确定位标签地位,从而获取标签或者标签属性中内容的工具。bs4 默认自带的解析器,然而官网举荐的是更弱小 速度更快的 lxml 解析器

其余解析器的优缺点

一、bs4 的装置

pip install bs4
pip install lxml

应用 bs4 解析时,举荐应用 lxml 解析器。这个在用 xpath 解析的时候也会用到

二、bs4 解析原理

  • 首先实例化一个 BeautifulSoup 对象,并且将页面源代码加载到这个对象里
  • 调用 BeautifulSoup 对象中的相干属性或者办法进行标签定位和数据提取
1、如何实例化 BeautifuSoup 对象
a. 导入 bs4 包
from bs4 import BeautifulSoup
b. 实例化对象

网页源代码,又分为本地曾经长久化的 HTML 文件和网络上间接获取的源代码。

如果是本地曾经长久化的文件,能够通过上面的形式将源代码加载到 bs4 对象中

fp = open('xxx.html', 'r', encoding='utf-8')
# lxml: 解析器
soup = BeautifulSoup(fp, 'lxml') 

如果是通过 requests 库获取的网页源代码,通过上面的形式进行加载

response = requests.get(url)
html = response.text
soup = BeautifulSoup(html, 'lxml')

c. 数据解析的办法和属性

bs4 可能将简单的 HTML 转换成一个树形构造,每个节点都是 Python 对象。

soup.tagName(标签名): 返回的是文档中第一次呈现 tagName 对应的标签及其相应内容

soup.tageName1.tageName2:返回 tag1 中 tage2 的标签及其内容

soup.find:等同于 soup.tagName,返回第一个匹配到的对象

soup.find_all:返回所有的匹配到的对象。

通过查看源码会发现,find 的实质其实就是调用了 find_all,而后返回第一个元素

参数解释:

  • name : 要查找的标签名(字符串、正则、办法、True)
  • attrs: 标签的属性
  • recursive: 递归
  • text: 查找文本
  • **kwargs : 其它 键值参数
    def find(self, name=None, attrs={}, recursive=True, text=None,
             **kwargs):
        """Return only the first child of this Tag matching the given
        criteria."""
        r = None
        l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
        if l:
            r = l[0]
        return r

[外链图片转存失败, 源站可能有防盗链机制, 倡议将图片保留下来间接上传 (img-iXUox6yw-1611066850753)(C:UsersAdministratorAppDataRoamingTyporatypora-user-imagesimage-20210103164834540.png)]

上图是我从某网站截取的局部画面,翻译成 HTML 如下(只保留了对本次剖析有用的局部,为了不便浏览删除了地址的域名信息)

<html>
 <head><titel> 测试 Title</titel></head>
 <body>
  <div class="test">
      <ul>
          <li> <a href="zhaosi.html">![](123456789.jpg)<p> 尼古拉斯赵四 </p></a> </li>
      </ul>
  </div>
  <div class="nr_zt w1180">
   <ul>
    <li> <a id="star" href="zhengshuang.html">![](5940f2cd6b759.jpg)<p> 郑爽 </p></a> </li>
    <li> <a id="star" href="zhuyilong.html">![](5b56e0fabf5bf.jpg)<p> 朱一龙 </p></a> </li>
    <li> <a id="star" href="zhoudongyu.html">![](5a28b93be8155.jpg)<p> 周冬雨 </p></a> </li>
    <li> <a id="star" href="huyitian_1.html">![](5aa36dfbe5f61.jpg)<p> 胡一天 </p></a> </li>
    <li> <a id="star" href="yiyangqianxi.html">![](5a28d243b0382.jpg)<p> 易烊千玺 </p></a> </li>
    <li> <a id="star" href="dilireba.html">![](5a28b69334087.jpg)<p> 迪丽热巴 </p></a> </li>
   </ul>
  </div>
 </body>
</html>

看上面几个例子

# 获取第一个 li 标签
# <li> <a href="http://www.win4000.com/mt/zhengshuang.html">![](http://pic1.win4000.com/tj/2017-06-14/5940f2cd6b759.jpg)<p> 郑爽 </p></a> </li>
print(soup.li)
# # 获取第一个 li 标签中 a 标签
# <a href="http://www.win4000.com/mt/zhengshuang.html">![](http://pic1.win4000.com/tj/2017-06-14/5940f2cd6b759.jpg)<p> 郑爽 </p></a>
print(soup.li.a)
#获取第一个 li 标签中 a 标签
print(soup.find('li').a)
# 获取所有 li 标签
print(soup.find_all('li'))
# 获取 title 标签
print(soup.title)
# 获取 a 标签的父级标签
print(soup.a.parent)
# 获取 a 标签的父级标签的名字
print(soup.a.parent.name)

如何获取 HTML 中的 href?

剖析:href 是 a 标签中的一个属性,而 a 标签又在 li 标签中

在 bs4 中提取标签中的属性能够通过 attrs 来获取

from bs4 import BeautifulSoup

fp = open('baidu.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')

# 如果获取一个能够这样写
result = soup.a.attrs['href']
# zhaosi.html
print(result)

# 获取全副, 可通过先获取 a 标签 而后遍历获取
all_result = soup.find_all('a')
for i in all_result:
    print(i.attrs['href'])

print("*" * 40)
#  如果我只想获取 id = star 的 href,须要先对 id 进行筛选
# 返回所有蕴含 id=star 的 a 标签
star_result = soup.find_all('a', id='star')
for i in star_result:
    print(i.attrs['href'])

# 返回蕴含 id 的标签(只有有 id 属性,并且有值的标签都返回)soup.find_all(id=True)

# 假如尼古拉斯赵四 不是第一个 a 标签中的内容. 提取对应的 href
# 须要先定位 class=‘test’对应 div 的地位
# 办法一:result = soup.find('div', 'test')
print(result.a['href'])

# 办法二(class 为 python 中关键字,因而查找 html 中的 class 属性须要增加个下划线 class_)result1 = soup.find('div', class_='test')
print(result1.a['href'])

# 办法三
result2 = soup.find('div', attrs={'class': 'test'})

# 获取第一个 a 标签中的文本内容
print(soup.a.text)

a_result = soup.find_all('a')
for i in a_result:
    # 生成的是一个迭代器
    print(i.strings)
    print(list(i.strings))
    print(i.string)
    print(i.text)

其余补充

# 返回子孙节点
# children 返回迭代器
result = soup.a.children
for i in result:
    print(i)

# 返回子孙节点,contents 返回列表
r = soup.a.contents
print(r)

# 能够通过正则对某个属性进行匹配
# 比方返回 href 中以 zh 结尾的标签
import re
reg = re.compile('^zh')
result = soup.find_all(href=reg)
print(result)

选择器

bs4 十分弱小,还反对 css 选择器。通过 select 来实现

<html>
 <head><titel> 测试 Title</titel></head>
 <body>
  <div class="test">
      <ul>
          <li> <a href="zhaosi.html">![](123456789.jpg)<p> 尼古拉斯赵四 </p></a> </li>
      </ul>
  </div>
  <div class="nr_zt w1180">
   <ul>
    <li> <a id="star" href="zhengshuang.html">![](5940f2cd6b759.jpg)<p> 郑爽 </p></a> </li>
    <li> <a id="star" href="zhuyilong.html">![](5b56e0fabf5bf.jpg)<p> 朱一龙 </p></a> </li>
    <li> <a id="star" href="zhoudongyu.html">![](5a28b93be8155.jpg)<p> 周冬雨 </p></a> </li>
    <li> <a id="star" href="huyitian_1.html">![](5aa36dfbe5f61.jpg)<p> 胡一天 </p></a> </li>
    <li> <a id="star" href="yiyangqianxi.html">![](5a28d243b0382.jpg)<p> 易烊千玺 </p></a> </li>
    <li> <a id="star" href="dilireba.html">![](5a28b69334087.jpg)<p> 迪丽热巴 </p></a> </li>
   </ul>
  </div>
 </body>
</html>
from bs4 import BeautifulSoup

fp = open('baidu.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')

# 返回一个所有 a 标签的列表
result = soup.select('a')
# 返回第一个
result1 = soup.select('a')[0]

"""class 选择器:.className"""
# 一层一层的进行抉择,用 > 连贯  即 > : 示意一个层级
# 输入 class = nr_zt 下 ul 下的 li 下的 a 标签汇合
a = soup.select('.nr_zt > ul > li > a')
# 多个层级关联,应用 空格。# 输入 class= 'nr_zt' 下的 a 标签汇合
b = soup.select('.nr_zt a')


"""id 选择器:# idName"""
result = soup.select('#star')

# 通过 href 属性查找,返回列表
soup.select('a[href="zhengshuang.html"]')

# 获取对应标签中 img 标签的 src 值
a = soup.select('a[href="zhengshuang.html"]')[0]
print(a.img['src']) # 5940f2cd6b759.jpg

以上就是 bs4 的罕用操作代码,实际上在具体的爬虫过程中,匹配的形式比拟灵便,所以大家也不必能够的去背,只须要记住其原理即可。

退出移动版