文章目录
- 写在前面
- python 爬虫
- BeautifulSoup库是什么
- BeautifulSoup的安装
- 解析器对比
- BeautifulSoup的使用
- BeautifulSoup 库中的4种类
- 获取标签
- 获取指定标签
- 获取标签的的子标签
- 获取标签的的父标签(上行遍历)
- 获取标签的兄弟标签(平行遍历)
- 获取注释
- 根据条件查找标签
- 根据CSS选择器查找标签
写在前面
本文主要介绍了python爬虫
中的BeautifulSoup库的安装和使用,如果是爬虫小白,请先看文章爬虫入门与requests库的使用,再来看本文章,这样你会有更深刻地理解,当然,大佬随意。
python 爬虫
BeautifulSoup库是什么
BeautifulSoup是一个用于解析 HTML
和 XML
文档的 Python 库
,它帮助你从网页中提取数据。这个库非常灵活,并且可以与多种不同的解析器一起工作,比如 Python 内置的 html.parser
、lxml
或者 html5lib
。
BeautifulSoup的安装
想要安装BeautifulSoup库,则需要执行以下安装命令:
pip install bs4
pip install beautifulsoup4
pip install soupsieve
pip install lxml
解析器对比
如上图,其中markup为一个html
文件或者html
代码(字符串形式)。
BeautifulSoup的使用
BeautifulSoup 库中的4种类
BeautifulSoup
将复杂的 HTML 文档转换成由 Python 对象构成的树形结构,主要包括以下四种类型的对象:Tag
, NavigableString
, BeautifulSoup
, 和 Comment
。
Tag
:表示标签。NavigableString
:表示标签之间的文本内容。BeautifulSoup
:表示整个解析后的文档。Comment
:一种特殊的NavigableString
,表示 HTML 中标签之间的注释。
获取标签
获取指定标签
Tag(获取标签):
from bs4 import BeautifulSoup
with open(file="test.html", mode='r', encoding='utf-8') as fp:
soup = BeautifulSoup(markup=fp, features='html.parser')
# 解析html文件并将解析结果返回
# 查找并获取HTML文档中的第一个 <h2> 标签。
h2_tag = soup.h2
# 打印找到的 <h2> 标签(如果有的话)。如果没有找到 <h2> 标签,则打印None。
print(h2_tag)
# 打印 <h2> 标签的数据类型。如果是有效的标签,它将是bs4.element.Tag 类型;
#如果没有找到标签,则是NoneType。
print(type(h2_tag))
# 打印标签名
print(h2_tag.name)
# 修改标签名后打印,并不会修改原HTML文档中的标签名
h2_tag.name = 'h3'
print(h2_tag.name)
# 获取标签之间的文本内容(纯文本内容),如果标签中还有标签,则返回None
print(h1_tag.string)
# 获取标签之间的文本内容,如果标签中还有标签,
#则获取所有二级标签的内容(以换行分隔)
# 最终将所有的文本内容拼接成一个字符串返回
print(h1_tag.get_text())
img_tag = soup.img #获取到第一个<img>标签
# 以字典方式获取标签的所有属性的键和值
print(img_tag.attrs)
# 获取img标签中属性alt的值,如果属性不存在报KeyError错误
print(img_tag['alt'])
# 获取img标签中属性alt的值,如果属性不存在返回None
print(img_tag.get('alt'))
print(img_tag.attrs.get('alt'))
# 以上两种方式是同样的效果
img_tag['alt'] = '修改后的alt'
# 打印修改后的alt的值
print(img_tag['alt'])
# 删除属性
del img_tag['alt']
# 打印标签内容
print(img_tag)
下面详细地讲解一下需要注意的方法:
标签名.get_text():
# 获取标签之间的文本内容,如果标签中还有标签,
# 则获取所有二级标签的文本内容(以换行分隔)
# 最终将所有的文本内容拼接成一个字符串返回
print(h1_tag.get_text())
<div>
<p>Hello</p>
<span>World</span>
</div>
div_tag.get_text() # 输出: '\nHello\nWorld\n'
div_tag.get_text(strip=True) # 输出: 'HelloWorld'
div_tag.get_text(separator=" | ") # 输出: '\n | Hello | \n | World | \n'
获取标签的的子标签
- 获取指定标签的所有子节点标签及文本内容(列表形式返回)
标签名.contents:
标签名.contents
#获取当前标签的直接子节点列表(不含子孙)
<div>
<p>Hello</p>
<span>World</span>
</div>
div_tag.contents
# 输出: ['\n', <p>Hello</p>, '\n', <span>World</span>, '\n']
注意:与上面的
标签名.get_text()
作区别
- 获取指定标签的所有子节点标签及文本内容(迭代器形式返回)
soup.标签名.children
#获得标签对应的子标签和子字符串(回车)的迭代类型,可以直接用于迭代
- 获取指定标签的所有子孙后代节点标签及文本内容(迭代器形式返回)
soup.标签名.descendants
# 获得标签对应的所有的子孙标签和子孙字符串的迭代类型,可以直接用于迭代
获取标签的的父标签(上行遍历)
- 获取指定标签的父标签(迭代器形式返回)
soup.标签名.parent
#获得标签对应的父标签
- 获取指定标签的所有先辈标签(迭代器形式返回),
从直接父级开始,逐级向上到文档根节点
soup.标签名.parents
#获得标签对应的先辈标签的迭代类型,可以直接用于迭代
获取标签的兄弟标签(平行遍历)
- 获取指定标签相邻的下一个平行标签(按html代码顺序)
soup.标签名.next_sibling
#返回按html代码顺序的下一个平行节点标签
- 获取指定标签相邻的上一个平行标签(按html代码顺序)
soup.标签名.previous_sibling
# 返回html代码顺序的上一个平行节点标签
- 获取指定标签后续的所有平行标签(即按html代码顺序排在指定标签后的所有兄弟标签)
soup.标签名.next_siblings
# 返回html代码顺序的后续所有平行节点标签
- 获取指定标签前序的所有平行标签(即按html代码顺序排在指定标签前的所有兄弟标签)
soup.标签名.previous_siblings
#返回html代码顺序的前序所有平行节点标签
获取注释
想要获取和操作html文件或代码
中的注释,需要通过 BeautifulSoup 的 Comment
类。
Comment类的作用;
- 提取注释内容:从 HTML/XML 中提取被
<!-- ... -->
包裹的注释文本。- 判断节点类型:识别某个字符串节点是否为注释。
定位注释:
注释在 BeautifulSoup 中被解析为 Comment
类型的特殊字符串对象,可通过以下方式获取:
from bs4 import BeautifulSoup, Comment
html = '''
<div>
<p>正文内容</p>
<!-- 这是一个隐藏的注释 -->
</div>
'''
soup = BeautifulSoup(html, 'html.parser')
# 方法1:遍历所有字符串节点,筛选出注释
comments = soup.find_all(string=lambda text: isinstance(text, Comment))
for comment in comments:
print("注释内容:", comment) # 输出: 这是一个隐藏的注释
# 方法2:直接通过标签访问(若注释在标签内)
div_tag = soup.div
comment_in_div = div_tag.find(string=lambda text: isinstance(text, Comment))
print(comment_in_div) # 输出: 这是一个隐藏的注释
操作注释:
- 提取注释文本:直接获取
Comment
对象的字符串。 - 替换或删除注释:
# 找到对应的注释
# 替换注释为普通文本
comment = div_tag.find(string=lambda text: isinstance(text, Comment))
comment.replace_with("替换后的文本")
# 删除注释
comment.extract()
例子( 提取注释中的日期):
from bs4 import BeautifulSoup, Comment
html = '''
<div class="article">
<!-- 文章发布时间:2023-10-01 -->
<h1>标题</h1>
<p>正文内容...</p>
</div>
'''
soup = BeautifulSoup(html, 'html.parser')
div_tag = soup.find('div', class_='article')
#定位到了指定的标签
# 查找注释并提取日期
comment = div_tag.find(string=lambda text: isinstance(text, Comment))
if comment:
date = comment.strip().split(":")[-1]
print("发布日期:", date) # 输出: 2023-10-01
根据条件查找标签
soup.find_all(name,attrs,string)
#name 目的标签名,同时查找多个标签时格式为
#name=['标签名1','标签名2'],name=True时,查找出所有标签
#attrs 目的标签中的属性值,查找标签名与name相同,同时标签属性的所有值中有attrs的标签
#也可以直接对属性进行查找 soup.find_all(class="title")
# 查找class属性的值为"title"的标签
link = soup.find_all('a', {'class': 'sister', 'id': 'link2'})
#同时对多个属性查找
#string 对标签文本内容的查找(支持使用正则表达)
#limit 限制返回结果的数量,类似于 SQL 中的 `LIMIT` 关键字。
#当搜索到的结果数量达到限制时,停止搜索并返回结果
#recursive 控制是否检索所有子孙节点。
#如果设置为 `False`,则只搜索直接子节点
#函数作用:以列表的形式返回查找结果
#soup(……) ----------soup.find_all(……)
如上,为常用的查找方法,其中soup.find()
的作用是查找第一个匹配的标签,找到后立马返回,不再继续查找,其参数与soup.find_all(……)
相同。
根据CSS选择器查找标签
#可以直接使用标签名查找元素
title_tags = soup.select('title')
print(title_tags)
#使用(.类名)选择类查找元素
sister_links = soup.select('.sister')
print(sister_links)
#使用井号(`#id名`)选择ID查找元素
link1 = soup.select('#link1')
print(link1)
#使用空格选择后代元素
bold_text = soup.select('p b')
print(bold_text)
#使用大于号(`>子标签名`)选择直接子元素
direct_children = soup.select('body > p')
print(direct_children)
# 输出: [<p class="title"><b>The Dormouse's story</b></p>,
#<p class="story">...</p>]
# 输出body下所有子标签中的p标签
#可以根据属性来选择元素
specific_link = soup.select('a[href="http://example.com/lacie"]')
print(specific_link)
#可以使用伪类选择器,例如选择第一个元素
first_sister = soup.select('.sister:first-child')
print(first_sister)
#选择class="sister"的标签下的第一个子标签