目录
活动地址:CSDN21天学习挑战赛
**
学习日记 Day18
**
一、BeautifulSoup4库简单介绍
BeautifulSoup4是一个可以从HTML或XML中提取数据的python库。它能够通过你喜欢的转换器实现管用的文档导航、查找、修改文档的方式。BeautifulSoup会帮你节省数小时甚至数天的工作时间。
BeautifulSoup4将网页转换为一颗DOM树:
⚪ 下载BeautifulSoup4模块
在cmd命令中输入pip install beautifulsoup4命令,安装即可。
⚪ beautifulsoup4解析库
BeautifulSoup在解析时实际上依赖解析器,它除了支持python标准库中的HTML解析器外,还支持一些第三方解析器(比如xml):
解析器 | 使用方法 | 优势 | 劣势 |
python标准库 | BeautifulSoup(html,'html.parser') | pyhton内置标准库、执行速度适中、文档容错能力强 | python2.7.3及python3.2.2之前的版本文档容错能力差 |
lxml HTML解析库 | BeautifulSoup(html,'lxml') | 速度快、文档容错能力强 | 需要安装C语言库 |
lxml XML解析库 | BeautifulSoup(html,'xml') | 速度快、唯一支持的XML的解析器 | 需要安装C语言库 |
htm5lib解析库 | BeautifulSoup(html,'html5llib') | 最好的容错性、以浏览器的方式解析文档、生成HTMLS格式的文档 | 速度慢、不依赖外部扩展 |
常用的解析器是lxml HTML解析器,其次是html5lib。
二、beautifulsoup4的使用
1. 基础操作
⚪ 读取HTML字符串
from bs4 import BeautifulSoup
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1" name="element">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<a href="https://www.baidu.com">百度官网</a>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
# 创建对象
soup = BeautifulSoup(html,'lxml')
⚪ 读取HTML文件
from bs4 import BeautifulSoup
# 创建对象
soup = BeautifulSoup(open('test.html'),'lxml')
⚪ 基本方法
from bs4 import BeautifulSoup
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1" name="element">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<a href="https://www.baidu.com">百度官网</a>
<li class="element">Bar</li>
</ul>
</div>
</div>
'''
# 创建对象
soup = BeautifulSoup(html,'lxml')
# 缩进格式
print(soup.prettify()) # 以缩进格式打印html字符串
print('*'*50)
# 获取title标签的所有内容
print(soup.title)
# 获取title标签的名称
print(soup.title.name)
# 获取title标签的文本内容
print(soup.title.string)
# 获取head标签的所有内容
print(soup.head)
# 获取第一个div标签中的所有内容
print(soup.div)
# 获取第一个div标签的id的值
print(soup.div['id'])
# 获取第一个a标签中的所有内容
print(soup.a)
# 获取所有的a标签中的所有的内容
print(soup.find_all('a'))
# 获取id='ul
print(soup.find(id='ul'))
# 获取所有的a标签,并遍历打印a标签的文本值
for item in soup.find_all('a'):
print(item.get('href'))
# 获取所有的a标签,并遍历打印a标签的文本值
for item in soup.find_all('a'):
print(item.get_text())
2. 对象种类
BeautifulSoup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以归纳为4种:Tag,NavigableString,BeautifulSoup,Comment。
⚪ Tag,通俗说就是HTML种的一个个标签,比如:
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>','lxml')
tag = soup.b
print(tag)
print(type(tag))
显示结果:
<b class="boldest">Extremely bold</b>
<class 'bs4.element.Tag'>
Tag有很多方法和属性,这里介绍tag种最重要的属性name和attributes。
name属性:
# 输出tag的name
print(tag.name) # 打印 b
# 如果改变了tag的name,将影响所有通过当前Beautiful Soup对象生成的HTML文档
tag.name='b1'
print(tag) # 打印 <b1 class="boldest">Extremely bold</b1>
Attributes属性:
# 获取class属性
print(tag['class']) # 输出 ['boldest']
# 直接获取属性
print(tag.attrs) # 输出 {'class': ['boldest']}
tag的属性可以被添加、修改和删除:
# 添加 id 属性
tag['id'] = 1
print(tag)
# 修改 class 属性
tag['class'] = 'tl1'
print(tag)
# 删除 class 属性
del tag['class']
print(tag)
显示结果:
<b1 class="boldest" id="1">Extremely bold</b1>
<b1 class="tl1" id="1">Extremely bold</b1>
<b1 id="1">Extremely bold</b1>
⚪ NavigableString,用.string获取标签内部的文字。
print(soup.b.string) # 输出 Extremely bold
print(type(soup.b.string)) # 输出 <class 'bs4.element.NavigableString'>
⚪ BeautifulSoup,表示一个文档的内容,可以获取它的类型、名称以及属性。
print(soup.name) # 输出 [document]
print(type(soup.name)) # 输出 <class 'str'>
print(soup.attrs) # 文档本身的属性为空 输出 {}
⚪ Comment,是一个特殊类型的NavigableString对象,其输出的内容不包括注释符号。
print(soup.b) # 输出 <b class="boldest">Extremely bold</b>
print(soup.b.string) # 输出 Extremely bold
print(type(soup.b.string)) # 输出 <class 'bs4.element.NavigableString'>
3. find_all()搜索文档树
find_all(name,attrs,recursive,text,**kwargs)
⚪ 参数name :查找所有名字为name的tag,字符串对象会被自动忽略掉。
- 匹配字符串:查找与字符串完整匹配的内容,如下用于查找文档中所有的<a>标签。
- 匹配正则表达式:如果传入正则表达式作为参数,BeautifulSoup会通过正则表达式的match()来匹配内容。
- 匹配列表:如果传入列表参数,BeautifulSoup会将与列表中任一元素匹配的内容返回
- 示例:
-
from bs4 import BeautifulSoup import re html = ''' <div class="panel"> <div class="panel-heading"> <h4>Hello</h4> </div> <div class="panel-body"> <ul class="list" id="list-1" name="element"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">Jay</li> </ul> <ul class="list list-small" id="list-2"> <li class="element">Foo</li> <a href="https://www.baidu.com">百度官网</a> <li class="element">Bar</li> </ul> </div> </div> ''' soup = BeautifulSoup(html,'lxml') # 查找与字符串完整匹配的内容 a_list = soup.find_all('a') print(a_list) # 返回所有表示<body>和<b>标签 for tag in soup.find_all(re.compile('^b')): print(tag.name) # 返回所有<ul>标签和<a>标签 print(soup.find_all(['ul','a']))
显示结果:
-
[<a href="https://www.baidu.com">百度官网</a>] body PS E:\1_tempFile\1_learn_code\VSCode\python_test> & D:/IDE/Python/python.exe e:/1_tempFile/1_learn_code/VSCode/python_test/python_beautifulsoup4/read_html.py [<a href="https://www.baidu.com">百度官网</a>] body [<ul class="list" id="list-1" name="element"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">Jay</li> </ul>, <ul class="list list-small" id="list-2"> <li class="element">Foo</li> <a href="https://www.baidu.com">百度官网</a> <li class="element">Bar</li> </ul>, <a href="https://www.baidu.com">百度官网</a>]
⚪ 参数kwargs :可以以标签=值的方式查找所有该标签下的内容。
-
from bs4 import BeautifulSoup soup = BeautifulSoup(open('test.html'),'lxml') print(soup.find_all(id='list-1'))
显示结果:
-
[<ul class="list" id="list-1" name="element"> <li class="element">Foo</li> <li class="element">Bar</li> <li class="element">Jay</li> </ul>]
⚪ 参数text:通过text参数可以搜索文档中的字符串内容,于name参数的可选值一样,text参数接受字符串,正则表达式、列表。
-
soup = BeautifulSoup(open('test.html'),'lxml') # 匹配字符串 print(soup.find_all(text='a')) # 匹配正则表达式 print(soup.find_all(text=re.compile('^b'))) # 匹配列表 print(soup.find_all(text=['ui','li']))
4. CSS选择器
在使用BeautifulSoup解析库时,经常结合CSS选择器来提取数据。
⚪ 根据标签名查找:比如传递 li 就会选择所有 li 标签
soup = BeautifulSoup(open('test.html'),'lxml')
print(soup.select('li'))
显示结果:
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
⚪ 根据类名class查找:.line 表示选择class="line"的所有标签。用 . 代表class。
soup = BeautifulSoup(open('test.html'),'lxml')
print(soup.select('.panel-heading'))
显示结果:
[<div class="panel-heading">
<h4>Hello</h4>
</div>]
⚪ 根据id查找:#box 表示选取id=box的所有标签,#代表id
soup = BeautifulSoup(open('test.html'),'lxml')
print(soup.select('#list-1'))
显示结果:
[<ul class="list" id="list-1" name="element">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
⚪ 根据属性的名字查找:class和id分别使用 . 和#代表它们。其它的属性可以按照 input[name="username"]的格式查找 name="username"的标签。
soup = BeautifulSoup(open('test.html'),'lxml')
print(soup.select('ul[name="element"]'))
显示结果:
[<ul class="list" id="list-1" name="element">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
⚪ 标签+类名或id的形式
soup = BeautifulSoup(open('test.html'),'lxml')
print(soup.select('ul#list-1'))
# 查找id为list-1的ul标签
print('='*40)
# 查找class为list的ul标签
print(soup.select('ul.list'))
显示结果:
[<ul class="list" id="list-1" name="element">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>]
========================================
[<ul class="list" id="list-1" name="element">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
</ul>, <ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<a href="https://www.baidu.com">Baidu</a>
<li class="element">Bar</li>
</ul>]
Process finished with exit code 0
⚪ 查找直接子元素
soup = BeautifulSoup(open('test.html'),'lxml')
# 查找id="list-1"的标签下的直接子标签li
print(soup.select('#list-1>li'))
⚪ 查找子孙标签
soup = BeautifulSoup(open('test.html'),'lxml')
# .panel_body 与 li之间是空格,表示查找class=panel_body的标签下的子标签或孙标签li
print(soup.select('.panel_body li'))
显示结果:
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
⚪ 获取某个标签的属性
soup = BeautifulSoup(open('test.html'),'lxml')
# 先获取到 <div class="panel_body">
div=soup.select('.panel_body')[0]
# 再获取a标签下的href属性
print(div.select('a')[0]['href'])
显示结果:
https://www.baidu.com
⚪ 获取文本内容
■ 使用string属性:获取某个标签下的文本内容,强调一个标签,不含嵌套内容,返回字符串
soup = BeautifulSoup(open('test.html'),'lxml')
# 先获取到<div class="panel_body">
div = soup.select('.panel_body')[0]
# 再获取下面的<a>标签下的内容
print(div.select('a')[0].string)
显示结果:
Baidu
■ 使用strings属性:获得某个标签下的所有文本内容,可以嵌套,返回一个生成器,可以用list转换为列表
soup = BeautifulSoup(open('test.html'),'lxml')
# 先获取到<div class="panel_body">
div = soup.select('.panel_body')[0]
print(div.strings)
print(list(div.strings))
显示结果:
<generator object Tag._all_strings at 0x000001BE4A405CF0>
['\n', '\n', 'Foo', '\n', 'Bar', '\n', 'Jay', '\n', '\n', '\n', 'Foo', '\n', 'Baidu', '\n', 'Bar', '\n', '\n']
■ 使用stripped_strings:和strings属性类似,不同在于stripped_strings会去掉字符串头部和尾部的空格和换行符
soup = BeautifulSoup(open('test.html'),'lxml')
# 先获取到<div class="panel_body">
div = soup.select('.panel_body')[0]
print(div.stripped_strings)
print(list(div.stripped_strings))
显示结果:
<generator object Tag.stripped_strings at 0x0000026D05935CF0>
['Foo', 'Bar', 'Jay', 'Foo', 'Baidu', 'Bar']
■ 使用get_text():获取所有字符串,包含嵌套,不过会把所有字符串拼接为一个再返回。
soup = BeautifulSoup(open('test.html'),'lxml')
# 先获取到<div class="panel_body">
div = soup.select('.panel_body')[0]
print(div.get_text())
显示结果:
Foo
Bar
Jay
Foo
Baidu
Bar