本实验将讲解 Beautiful Soup 4 库解析 HTML 的常见用法,它的中文名字是「美丽汤」。在使用 pip 安装该库时的名字是 beautifulsoup4 ,在使用该库时包的名字是 bs4 ,要注意它们的区别。
Beautiful Soup 4 专注于解析 HTML / XML 源码并提取想要的信息,也就是我们在使用爬虫工具爬取页面源码后处理数据的工作。在学习本节实验的时候,重点关注 bs4 中的语义化编码获取标签内容以及两个方法 find_all
与 select
的用法,掌握以上 2 点,bs4 最核心的知识已经被你掌握。
知识点
- Beautiful Soup 库常用属性与方法
- Beautiful Soup 实操解析数据
Beautiful Soup 库常用属性与方法
Beautiful Soup 4 简介
Beautiful Soup 4 是 Python 的一款解析库,为了书写方便下文统一用 bs4 来描述。跟 lxml
一样,bs4 也是一个 HTML/XML 解析库,主要配合 requests 库实现爬虫程序。
bs4 库默认使用的 Python 标准库中的 HTML 解析器,即 html.parser
(Python 的内置标准库),使用该方式的解析速度慢,原因是该方式在解析的时候会载入整个文档之后再解析整个 DOM 树,导致内存开销变大,性能降低,所以现在使用 bs4 的时候都是配合 lxml
库进行,本实验也围绕 bs4 与 lxml 展开。
在开始之前,你需要明确一件事情,bs4 会将 HTML 文档转换成一个复杂的树形结构,每个结点都是一个对象,这些对象可以归纳成 4 种,后文有针对这 4 种对象名称的说明。
先看一下待解析的页面,我们选择 人人都是产品经理书单页面,本实验目的是学习 bs4 的用法,故目标为抓取书籍封面图片链接与书籍名称。为避免目标网站改版,我们使用内部地址替换。
https://labfile.oss.aliyuncs.com/courses/3086/books.html
学习新库之前,需要先建立一个整体的认知,那么咱们先运行一段代码,了解一下 bs4 ,顺便说明一下 bs4 解析之后的 4 种对象。
特别说明:运行代码前需要先通过 sudo pip install beautifulsoup4
在实验楼 WebIDE 中安装该库。
将如下代码写入 /home/project/test_bs4.py
文件:
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36 Edg/86.0.622.69'
}
def get_detail():
r = requests.get("https://labfile.oss.aliyuncs.com/courses/3086/books.html", headers=headers)
r.encoding = 'utf-8'
html_doc = r.text
soup = BeautifulSoup(html_doc, "lxml")
title_tag = soup.title
title_str = title_tag.string
# Tag 标签对象
print(type(title_tag))
# NavigableString 对象为字符串内容
print(type(title_str))
# BeautifulSoup 对象为文档的全部内容
print(type(soup))
# Comment 对象为文档注释内容
# print(type(comment))
if __name__ == "__main__":
get_detail()
代码运行之后输出结果如下,该输出包含了 3 种 bs4 中的对象,最后一种由于测试网站中不包含注释代码,故没有展示,大家可以自行测试即可,补充一下 bs4 中的四种对象,Tag
,NavigableString
,BeautifulSoup
,Comment
。
上文代码输出的结果就是该 4 种对象(Comment 因注释未输出)。
<class 'bs4.element.Tag'>
<class 'bs4.element.NavigableString'>
<class 'bs4.BeautifulSoup'>
本实验后续都会围绕以上 3 种对象展开,Comment
不在本实验内学习。
标签(节点)选择器(Tag)
Tag 其实对应的就是 HTML 中的一个个标签,直接调用标签的名称就可以选择到对应的标签,例如下述代码。
def get_detail():
r = requests.get("https://labfile.oss.aliyuncs.com/courses/3086/books.html", headers=headers)
r.encoding = 'utf-8'
html_doc = r.text
soup = BeautifulSoup(html_doc, "lxml")
# 获取 title 标签
title_tag = soup.title
print(title_tag)
# 获取 head 标签
head_tag = soup.head
print(head_tag)
# 获取 tag 标签
a_tag = soup.a
print(a_tag)
# 获取 p 标签
p_tag = soup.p
print(p_tag)
通过这种方式获取到的是网页文档中第一个符合的标签,在编写解析代码的时候,如果确定该标签只会出现一次,使用该方法可以快速获取到数据。
对于 Tag 对象有 2 个很重要的属性是 attrs
和 string
,即获取标签属性与标签的文本内容。
attrs 属性获取标签属性
a_tag = soup.a
print(a_tag.attrs)
输出结果如下,返回的是字典格式数据。
{'href': '/', 'class': ['u-flex', 'u-relative']}
该数据可以与下图做比对,你将清楚了解到数据对应关系。
获取某一具体属性值
在爬虫编写过程中经常会获取超链接的 href
属性或者图片的 src
属性,所以需要用到下述知识点。
a_tag = soup.a
print(a_tag.attrs)
# 通过 attrs 再获取
print(a_tag.attrs["href"])
# 直接获取 a 标签的 class 属性
print(a_tag["class"])
获取标签文本
爬虫编写中也离不开获取网页标签中的文本内容,例如获取超链接标签 a
中的文本,在 bs4 中获取到的文本也是一种特殊的对象,称作 NavigableString
,该对象的获取非常简单,只需要调用 Tag 对象的 string
属性即可。
title_tag = soup.title
print(title_tag.string)
初识 bs4 编写爬虫,先重点掌握这两个属性值 attrs
与 string
可以解决大部分数据获取场景。
上文提及的知识点都是获取单个网页标签或标签内容,在爬虫编写过程中,更多需要批量获取,这时用到的是 bs4 的方法选择器。
方法选择器
通过标签选择器选择网页元素整体速度快,但是并不灵活,所以在很多时候需要借助方法选择器(也称做文档树搜索方法)对网页元素进行查找。
首先要介绍的是最常用的两个方法,find_all
与 find
方法。
find_all
的语法格式如下:
find_all(name, attrs, recursive, text, **kwargs)
其中各参数说明如下:
- name,可以是标签名称,正则表达式,列表,自定义函数等内容;
- attrs,配合前面的标签增加属性过滤,可传递多属性;
- recursive,调用 Tag 的
find_all
方法时,bs4 会检索当前 Tag 的所有子孙节点,如果只想搜索 Tag 的直接子节点,可以使用参数recursive = False
; - text,通过文本检索,通过 text 参数可以检索文档中的字符串内容,与 name 参数一样, text 参数接受标签名 , 正则表达式 , 列表等内容;
- keyword,关键字参数,理解成按自定义属性检索即可。
以上是对 find_all
方法的参数说明,方法选择器包含很多内容,例如以下方法,它们的使用都与 find_all
基本一致,可以自行学习掌握。
- find_all 与 find
- find_parents 与 find_parent
- find_next_siblings 与 find_next_sibling
- find_previous_siblings 与 find_previous_sibling
- find_all_next 与 find_next
- find_all_previous 与 find_previous
接下来通过代码实际查看一下 find_all
方法的应用。find
方法语法格式与 find_all
一致,只是返回的是单一标签,不再赘述。
将如下代码替换 /home/project/test_bs4.py
文件中的同名函数:
def get_detail():
r = requests.get("https://labfile.oss.aliyuncs.com/courses/3086/books.html", headers=headers)
r.encoding = 'utf-8'
html_doc = r.text
soup = BeautifulSoup(html_doc, "lxml")
print(type(soup))
# 标签查找
h2_tags = soup.find_all('h2')
# print(h2_tags)
print(type(h2_tags))
# 属性加标签过滤
div_tags = soup.find_all('div', attrs={'class': 'jl-book-item'})
# print(div_tags)
print(type(div_tags))
# 标签列表
tag_list = soup.find_all(["h2", "h3"])
# print(tag_list)
print(type(tag_list))
代码运行之后,会发现返回值的数据类型依旧为 Tag
类型的聚合:
<class 'bs4.BeautifulSoup'>
<class 'bs4.element.ResultSet'>
<class 'bs4.element.ResultSet'>
<class 'bs4.element.ResultSet'>
使用 find
、find_all
等方法对网页进行解析是 bs4 中常用的知识,该内容需要牢牢掌握。
CSS 选择器
该选择器与 find_all
方法非常相似,通过一个 select
方法进行网页标签选择,学习该内容依旧需要对前端基础中的 HTML+CSS 有所了解。
通过标签名进行查找
该方式起始就是在使用 CSS 中的选择器,代码如下:
title_tag = soup.select("title")
print(title_tag)
需要特别注意的是 select
方法返回的数据类型是列表。接下来的知识内容将配合代码学习,在时间允许的情况下,尽量临摹几遍代码,做到牢牢掌握该内容,知识点不在进行文字特别说明,具体查找方式如下。
通过标签 class 属性(类名)进行查找
div_tag = soup.select(".jl-book-item")
print(div_tag)
通过 id 查找
div_tag = soup.select("#app")
print(div_tag)
通过任意属性查找
div_tags = soup.select("div[class='jl-book-item']")
print(div_tags)
直接子标签查找
# 注意 a 标签前的 >
a_tags = soup.select("div[class='jl-book-item'] > a")
print(a_tags)
后代标签查找(很多地方叫做组合查找)
# 注意 a 标签前的 空格
a_tags = soup.select("div[class='jl-book-item'] a")
print(a_tags)
获取内容
select
方法获取到网页标签都是列表对象,通过遍历形式输出,然后用 get_text
方法来获取标签的内容。
h3_tags = soup.select("div[class='jl-book-item'] h3")
for h3 in h3_tags:
print(h3.get_text())
Beautiful Soup 实操解析数据
本实验进行到这里已经对 bs4 库有了初步的认知,这些在爬虫初期编写阶段已经足够使用,接下来完成本实验对应的案例。
解析目标区域 div 标签
使用 bs4 需要先捕获目标数据所在的 div 标签,再对该标签进行拆解,目标区域 HTML 代码如下:
通过 bs4 的 select
方法进行解析,代码与运行结果如下(只展示 get_detail
函数部分代码,其余部分参照上文即可):
将如下代码替换 /home/project/test_bs4.py
文件中的同名函数:
def get_detail():
r = requests.get("https://labfile.oss.aliyuncs.com/courses/3086/books.html", headers=headers)
r.encoding = 'utf-8'
html_doc = r.text
soup = BeautifulSoup(html_doc, "lxml")
div_tags = soup.select("div[class='jl-book-item']")
print(div_tags)
代码运行之后获取到页面所有包含书籍的 DIV 标签。
解析 div 标签内部的超链接与标题
寻找到目标数据,在之后通过循环即可获取到 div 区域内的子标签,我们通过上文讲解到的三种不同方式获取网页标签。
div_tags = soup.select("div[class='jl-book-item']")
for div in div_tags:
# 获取购买链接
bug_link = div.a.attrs["href"]
# 获取书籍封面
img = div.find("img").attrs["src"]
# 获取书籍名称
name = div.select("h3")[0].get_text()
数据存储部分依旧留个你来独立完成。
实验总结
本实验重点部分由两个方法构成,通过 2 个核心的点去掌握一款完整的库,是编程学习过程中经常使用的技巧。在爬虫后面的学习之路上,你将接触到大量的第三方库,有请求类,有解析类,有存储类,如何快速的去掌握一款新库,就可以应用本实验的学习方式,从核心点扩展到整个面。
标签:书单,标签,抓取,爬虫,soup,tag,print,div,find From: https://www.cnblogs.com/zhangxuegold/p/17585627.html