主要流程:
- 导入BeautifulSoup类
- 传递初始化参数,并初始化
- 获取实例对象,操作对象获取解析、提取数据
1.初始化Beautiful Soup对象
从bs4库导入Beautiful Soup类 实例化一个对象。
from bs4 import BeautifulSoup
soup = BeautifulSoup(markup, features)
在实例化过程中,需要给Beautiful Soup这个类传递两个参数:
第一个参数:markup
- 参数解析:被解析的HTML字符串或文件内容
- 使用方式两种
(1)使用字符串变量
#使用第一步的html_str字符串变量
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_str)
(2)使用open()函数打开文件
#假设将html_str字符串写入了index.html中
from bs4 import BeautifulSoup
soup = BeautifulSoup(open(index.html))
第二个参数,features
- 参数解释:解析器的类型
- 使用方式:
(1)指定解析器,BeautifulSoup选择指定的解析器来解析文档
#指定lxml作为解析器
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_str, 'lxml')
(2)未指定解析器,BeautifulSoup选择最默认的解析器来解析文档
#解析html_str选择最默认的解析器
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_str)
在初始化对象的时候,需要给BeautifulSoup类传递两个参数。
2.认识选择器
选择器用来查找、定位元素,并获取数据。
选择器的分类
- 节点选择器
- 方法选择器
- CSS选择器
节点选择器是获取数据的基础方法,而方法选择器和CSS选择器则是查找、定位元素的常用选择。
(1)节点选择器
i 选择元素的方法
节点选择器就是使用tag对象来选择节点元素。而tag对象与HTML、XML的原生文档中的Tag相同,即标签。
<title>The Dormouse's story</title>
<a href="http://example.com/elsie class="sister" id="link1">Elsie</a>
title和a标签及里面的内容成为Tag对象。
- 格式
获取元素:soup.tag
#soup为Beautiful Soup4的对象
返回值:节点元素
- 实例
- 选取元素只需要在Beautiful Soup对象的后面加上标签名即可,例如:soup.title
- 获取到的节点是tag对象
- 当有多个相同节点的时候,只会返回第一个节点
ii 获取信息的方法
通过选择元素的方式,我们获取到了标签的全部信息,如果我们想要提取标签中的信息,可以使用如下方式:name获取名称、attrs获取属性、string获取内容。
- 获取名称
格式:soup.tag.name
返回值:字符串
示例:
#获取a标签的名字
soup.a.name
#输出结果
a
- 获取属性
格式:soup.tag.attrs
返回值:字典
示例:
#获取a标签的属性
soup.a.attrs
#输出结构
{'href':'http://example.com/elsie','class':['sister'],'id':'link1'}
- 获取内容
格式:soup.tag.string
返回值:字符串
示例:
#获取a标签的内容
soup.a.string
#输出结果
Elsie
iii 嵌套选择的方法
我们可以使用soup.tag获取bs4.element.Tag类型的节点,并获取他们的信息:
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
如果提取到的节点还嵌套这其他子节点
<head><title>The Dormouse's story</title></head>
那我们可以通过下面的操作方式来获取子节点的信息。
格式:soup.tag.tag
返回值:节点元素
示例:
#获取title
print(soup.head.title)
#打印获取到的title类型
print(type(soup.head.title))
#获取title的信息
print(soup.head.title.string)
#输出结果
<title>The Dormouse's story</title>
<class 'bs4.element.Tag'>
The Dormouse's story
soup.tag.tag:在Tag类型的基础上再次选择得到的依然是Tag类型,每次返回的结果相同,就可以进行嵌套选择了。
IV 关联选择的方法
在做选择的时候,有时候不能做到一部就选到想要的节点元素,例如示例中的第二个a节点:
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
需要先选中某一个节点元素,然后以它为基准再选择它的子节点、父节点、兄弟节点等。
子节点:contents、childeren;子孙节点:descendants;父节点:parent;祖先节点:parents;兄弟节点:next_sblings、previous_sblings、previous_sblings、next_sbling。
- 子节点
格式:soup.tag.contens
返回值:列表
示例:
#获取p节点的子节点
print(soup.p.contents)
#输出结果
['Once upon a time there were three little sisters; and their names were\n',<...]
格式:soup.tag.children
返回值:生成器(所以需要用for循环依次取出来)
示例:
#获取p节点的每一个子节点
print(soup.p.children)
for i, child in enumerate(soup.p.children):
print(i,child)
- 父节点
格式:soup.tag.parent
返回值:节点元素
示例:
#打印选取的a节点
print(soup.a)
#获取a节点的父节点
print(soup.a.parent)
#输出结果
#选取的a节点
<a class="sisier" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>
#所选a节点的父节点
<a class="story">Once upon a time there were three little sister; and their names were..
<a class="sisier" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>,
<a class="sisier" href="http://example.com/lacie" id="link2">Lacie</span></a> and
<a class="sisier" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
- 祖先节点
如果想要获取祖先节点,可以调用parents属性。
格式:soup.tag.parents
返回值:生成器
示例:
- 兄弟节点
如果想要获取同级的节点,使用sibing获取兄弟节点。
获取后面一个节点
格式:soup.tag.next_sibling
返回值:节点元素
示例:
#获取a节点的后面一个节点
print(soup.a.next_sibling)
#获取类型
print(type(soup.a.next_sibling))
#输出结果
<class 'bs4.element.NavigableString'>
- 获取后面所有的节点
格式:soup.tag.next_siblings
返回值:生成器
示例:
- 获取前面一个节点
格式:soup.tag.previous_sibling
返回值:节点元素
示例:
#获取a节点的前一个节点
print(soup.a.previous_sibling)
#获取类型
print(type(soup.a.previous_sibling))
#输出结果
Once upon a time there were three little sisters; and their names were <class 'bs4.element.NavigableString'>
- 获取前面的所有节点
格式:soup.tag.previous_siblings
返回值:生成器
示例:
#获取a节点前面的所有节点
print(soup.a.previous_siblings)
#获取类型
print(type(soup.a.previous_siblings))
#获取所有的内容
print(list(enumerate(soup.a.previous_siblins)))
#输出结果
<generator object previous_siblings at 0x102334468>
<class 'generator'>
[(0,'Once upon a time there were three little sisters; and their names were\n')]
子节点
- soup.tag.contents
- soup.tag.children
子孙节点
- soup.tag.descendants
父节点
- soup.tag.parent
祖先节点
- soup.tag.parents
兄弟节点
- soup.tag.next_sibling
- soup.tag.next_siblings
- soup.tag.previous_sibling
- soup.tag.previous_siblings
(2)CSS选择器
- 使用CSS选择器定位元素
- 嵌套选择
- 获取属性
- 获取文本
获取元素
格式:soup.select()
CSS选择器语法
i id选择器
id选择器需要 # 来定位元素,例如:获取第一个ul节点 #list-1
<div class="panel-body">
<ul class="list" id="list-1">
...
ii 类选择器
类选择器需要使用 . 来定位元素,例如:获取所有的ul.list
<div class="panel-body">
<ul class="list" id="list-1">
<li class="element"> Foo<li>
...
<ul class="list list-small" id="list-2">
...
iii 标签选择器
标签选择器需要使用标签来进行选择,例如:获取h4:h4
<div class="panel-heading">
<h4>Hello</h4>
<div>
IV 混合使用
获取第一个ul中的li节点,.panel-body #list-1 li
<div class="panel-body">
<ul class="list" id="list-1">
<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>
<li class="element"> Bar</li>
</ul>
</div>
示例:
- 获取class="panel-heading"的div
- 获取所有的li节点
- 获取第二个ul的li节点
- 获取第二个ul节点
html = '''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1">
<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>
<li class="element"> Bar</li>
</ul>
</div>
</div>
...
#导入Beautiful Soup类
from bs4 import BeautifulSoup
#传入参数,实例化这个类
soup=BeautifulSoup(html,'lxml')
#获取class="panel-heading"的div
print(soup.select(".panel.panel-heading"))
#获取所有的li节点 标签选择器
print(soup.select("ul li"))
#获取所有的li节点 类选择器
print(soup.select(".list.element"))
#获取第二个ul的li节点 id选择器
print(soup.select("#list-2 li"))
#获取第二个ul的li节点 类选择器
print(soup.select(".list-samll li"))
#获取第二个ul的li节点 列表获取
print(soup.select("ul")[1])
CSS选择器的高级用法:
i 嵌套选择
先选择一个节点,再获取这个节点下面的子节点。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select("ul"))
print(type(soup.select("ul")))
for ul in soup.select("ul"):
print(ul)
print(type(ul))
print(ul.select("li")) #这里表明可支持嵌套选择的使用
ii 获取属性
使用attrs属性来获取。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select("#list-2 li"))
for li in soup.select("#list-2 li"):
print(type(li))
print(li.attrs)
print(li.attrs['class'])
iii 获取文本
使用string和strings属性来获取
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.select("#list-2 li"))
for li in soup.select("#list-2 li"):
print(type(li))
print(li.attrs)
print(li.attrs['class'])
print(soup.select("#list-2"))
for ul in soup.select("#list-2"):
print(type(ul))
print(ul.strings)
print(list(ul.strings))
(3)方法选择器
前面的选择方法都是通过标签和属性来选择的,这种方法非常快,但是如果在比较复杂的页面中选择元素,无法精准定位到元素。
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
在HTML文档中存在多个<a>标签,我们无法使用节点选择器定位到第二个、第三个<a>标签。
因此我们将采用findall()和find()方法,通过传入参数的方法来定位。
获取所有符合条件的元素 | find_all() |
获取符合条件的第一个元素 | find() |
获取所有符合条件的祖先节点 | find_parents() |
获取符合条件的父节点 | find_parent() |
获取后面所有符合条件的兄弟节点 | find_next_siblings() |
获取后面第一个符合条件的兄弟节点 | find_next_sibling() |
获取前面所有符合条件的兄弟节点 | find_previous_siblings() |
获取后面所有符合条件的节点(包括子孙节点) | find_all_next() |
获取后面第一个符合条件的节点 | find_next() |
获取前面所有符合条件的节点(包括子孙节点) | find_all_previous() |
获取前面第一个符合条件的节点 | find_previous() |
获取后面第一个符合条件的兄弟节点 | find_next_sibling() |
方法选择器中的find_all()方法
find_all(name,attrs,recursive,text, **kwargs)
- name参数
作用:查找所有名字为name的节点(tag对象)
参数形式:
- 字符串
传入字符串参数,即标签名(tag),Beautiful Soup会查找与字符串完全匹配的内容
#寻找所有soup标签
print(soup.find_all('span'))
#输出结果
[<span>Elsie</span>]
- 正则表达式
传入正则表达式,Beautiful Soup会通过正则表达式的match()函数来匹配内容
#使用正则匹配以b开头的标签
import re
for tag in soup.find_all(re.compile('^b")):
print(tag.name)
#输出结果
body
- 列表
传入列表参数,Beautifl Soup会将与列表中任一元素匹配,并返回结果。
#使用列表选择包含a和span的所有标签
print(soup.find_all(['a','span']))
#输出结果
[<a class="sister" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>],
- True
True可以匹配任何值
#使用True选择文件中所有标签
for tag in soup.find_all(True):
print(tag.name)
#输出结果
html
head
title
...
- attrs参数
作用:查询含有接受的属性值的标签
参数形式:字典类型
#获取id为link1的标签
print(soup.find_all(attrs={id:'link1'}))
#输出结果
[<a class="sister" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>]
- kwargs参数
作用:接受常用的属性参数,如id何class
参数形式:变量赋值的形式
#获取id为link1的标签
print(soup.find_all(id='link1'))
#输出结果
[<a class="sister" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>]
这里直接传入id='link1',就查询到id为'link1'的节点元素了。而对class来说,它在Python中是一个关键词,需要加一个下划线,即class_='element'
#获取id为link1的标签
print(soup.find_all(class_='story'))
- text参数
作用:查询含有接收的文本的标签
参数形式:字符串
通过搜索文档中的字符串内容,来确定文件标签
#获取文本中包含Elsie内容
print(soup.find_all(text='Elsie')))
#输出结果
['Elsie']
可以与其他参数混合使用来过滤tag
print(soup.find_all['a',text='Elsie'])
#搜索a标签中含有Elsie的字符串
print(soup.find_all(text='story'))
#只比对story,会发现比对不上,需要把story前面的信息补充上
import re
print(soup.find_all(text=re.compile('.*?story')))
#使用text获取包含story的标签
#且必须写text
- limit参数
作用:用于限制返回结果的数量
参数形式:整数
#获取前两个a标签
print(soup.find_all('a',limit=2))
- recursive参数
作用:决定是否获取子孙节点
参数形式:布尔值,默认是True
print(soup.find_all('title'))
print(soup.find_all('title',recursive=False))
find_all()方法的使用:
- name参数用来接收tag名称,有四种形式:字符串,正则,列表和True
- attrs参数用来接收属性的键值对字典
- kwargs参数用来接收常用属性的变量赋值的形式 例如:id='link1',class="sister"
- text参数用来接收文本信息
- limit参数用来限制返回结果的数量
- recursive参数用来决定是否获取子孙节点
方法选择器中find()方法和其他方法
find()方法和find_all()方法区别在于:
- find_all()方法返回所有符合条件的元素列表,而find()方法就是返回符合条件的第一个元素
- 除了limit参数不能在find()方法中使用,find()方法的其他参数和find_all()的参数用法一样
find()方法:
作用:查找当前节点,符合条件的一个元素节点
范围:当前节点下的一个元素
- name参数
#获取a标签
print(soup.find('a'))
#输出结果
<a class="sister" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>
- attrs参数
#获取class等于sister的标签
print(soup.find(attrs={'class':'sister'))
#输出结果
<a class="sister" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>
- kwargs参数
#获取class等于sister的标签
print(soup.find(class_='sister'))
#输出结果
<a class="sister" href="http://example.com/elsie" id="link1"><span>Elsie</span></a>
- text参数
#获取文本中包含story的标签
print(soup.find(text=re.compile('.*?story')))
#输出结果
The Dormouse's story
- recursive参数
#获取文本中包含story的标签
print(soup.find('a', recursive=False))
#输出结果
None
(以上为学习Python爬虫之Beautiful Soup教程的学习笔记)