解析数据的Beautiful Soup模块

中文官方文档: https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/

1、使用Beautiful Soup 解析数据

        Beautiful Soup是一个用于从HTML和XML文件中提取数据的Python模块,BeautifulSoup自动输入文档转换为Unicode编码,输出文档转换为UTF-编码,开发者不需要考虑编码方式,除非文档没有指定编码方式,这时,Beautiful Soup就不能自动识别编码方式了,需要开发者说明以下原始编码方式就可以了。

1.1 Beautiful Soup的安装

        Beautiful Soup 3已经停止开发,目前使用的是Beautiful Soup 4,不过已经移植到了bs4当中,所以导入时,需要from bs4 import Beautiful Soup。如果没用使用Anaconda,则安装Beautiful Soup有以下三种方式:

● 如果使用的是最新版本的Debian或Ubuntu Linux,则可以使用系统软件管理器安装Beautiful Soup。命令:

apt-get install python-bs4

Beautiful Souop 4是通过PyPi发布的,可以通过easy_install或pip来安装。包名是beautifulsoup4,可以兼容Python2和Python3,安装命令:

easy_install beautifulsoup4 
或
pip install beautifulsoup4

注意:

在使用Beautiful Soup 4前,需要安装bs4库

pip install bs4

        如果当前的Beautiful Soup不是我们想要的版本,可以通过下载源码的方式进行安装,源码的下载地址为:'https://www.crummy.com/software/BeautifulSoup/bs4/download/',然后在控制台中打开源码的指定路径,输入命令python setup.py install 即可。

1.2 解析器

html5lib解析器

用来解析HTML的Python库,按照Web浏览器的方式解析HTML

解析器的比较

解析器

用法

优点

缺点

Python标准库

BeautifulSoup(markup,'html.parser')

Python标准库执行速度适中

(在Python2.7.3或3.2.2之前的版本中)文档容错能力差

lxml的HTML解析器

BeautifulSoup(markup,'lxml')

速度快,文档容错能力强

需要安装C语言库

lxml的XML解析器

BeautifulSoup(markup,'lxml-xml')

BeautifulSoup(markup,'xml')

速度快

唯一支持XML的解析器

需要安装C语言库

html5lib

BeautifulSoup(markup,'html5lib')

最好的容错性,以浏览器的方式解析我能当生成HTML格式的文档

速度慢,不依赖外部扩展

1.3 Beautiful Soup的简单应用

解析文档:

from bs4 import BeautifulSoup
html_doc = open('myBook.html',mode='r',encoding='utf-8')
soup = BeautifulSoup(html_doc,features='lxml')
# print(soup)
print(type(soup)) # <class 'bs4.BeautifulSoup'>
print(soup.prettify()) # 打印格式化的代码  prettify()格式化处理

1.3.1 获取节点

<--myBook.html-->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link href="css/style.min862f.css?v=4.1.0" rel="stylesheet">
    <title>案例</title>
</head>
<body class="fixed-sidebar full-height-layout gray-bg" style="overflow:hidden">
    <div id="wrapper">
        <p>段落1</p>
        <p>段落2</p>
    </div>
</body>
</html>

from bs4 import BeautifulSoup
# 创建模拟HTML代码的字符串
html_doc = open('myBook.html',mode='r',encoding='utf-8')
soup = BeautifulSoup(html_doc,'lxml')
print('head节点内容为:\n',soup.head)
print('body节点内容为:\n',soup.body)
print('title节点内容为:\n',soup.title)
print('p节点内容为:\n',soup.p)

说明:

        在打印P节点对应的代码时,只打印了第一个P节点,说明当有多个节点时,该选择方式只会获取第一个节点的内容,其他后面的节点讲被忽略。

还可以通过name属性获取节点的名称。

1.3.2 获取节点属性

通过调用attrs即可获取这个节点的所有属性、

from bs4 import BeautifulSoup
html_doc = """
<html>
<head>
    <title>横排响应式登录</title>
    <meta http-equiv="Content-Type" content="text/html" charset="utf-8"/>
    <meta name="viewport" content="width=device-width"/>
    <link href="font/css/bootstrap.min.css" type="text/css" rel="stylesheet">
    <link href="css/style.css" type="text/css" rel="stylesheet">
</head>
<body>
<h3>登录</h3>
<div class="glyphicon glyphicon-envelope"><input type="text" placeholder="请输入邮箱"></div>
<div class="glyphicon glyphicon-lock"><input type="password" placeholder="请输入密码"></div>
</body>
</html>
"""
soup = BeautifulSoup(html_doc,'lxml')
print('meta节点中属性如下:\n',soup.meta.attrs)
print('link节点中属性如下:\n',soup.link.attrs)
print('div节点中属性如下:',soup.div.attrs)

meta节点中属性如下:
 {'http-equiv': 'Content-Type', 'content': 'text/html', 'charset': 'utf-8'}
link节点中属性如下:
 {'href': 'font/css/bootstrap.min.css', 'type': 'text/css', 'rel': ['stylesheet']}
div节点中属性如下: {'class': ['glyphicon', 'glyphicon-envelope']}

        在获取节点中指定属性所对应的值时,除了使用上面的方式外,还可以不写attrs,直接在节点后面已中括号的形式直接添加属性名称来获取对应的值

print('meta节点中http-equif属性值为:',soup.meta['http-equif'])
print('link属性:',soup.link['href'])
print(soup.div['class'][0])
print(soup.div['class'][1])

1.3.3 获取节点包含的文本内容

print('title节点所包含的文本内容为:',soup.title.string)

1.3.4 嵌套获取节点内容

例: 通过"."嵌套获取节点内容

from bs4 import BeautifulSoup
html_doc = open('myBook.html',mode='r',encoding='utf-8')
soup = BeautifulSoup(html_doc,'lxml')
print('head节点内容如下:\n',soup.head)
print('head节点中title节点内容为:',soup.head.title)
print('head节点中的文本内容为:',soup.head.title.string)

1.3.5 关联获取

        在获取节点内容时,不一定都能做到一步获取指定节点中的内容,有时还需要先确认某一个节点,然后以该节点为中心获取对应的子节点,孙节点,父节点以及兄弟节点。

  • 获取子节点

实现获取某节点下所有子节点内容

        在获取某节点下面的所有子节点时,是用那个contents或者childrenn属性来实现,其中contents返回一个列表,在这个列表中的每个元素都是一个子节点内容,而children返回的则是一个“list_iterator”类型的可迭代对象。

from bs4 import BeautifulSoup
html_doc = open('myBook.html',mode='r',encoding='utf-8')
# 创建一个BeautifulSoup对象,获取页面正文
soup = BeautifulSoup(html_doc,features='lxml')
print("soup.head.contents:",soup.head.contents) # 返回是一个列表
print("soup.head.children:",soup.head.children) # 返回是一个list_iterator迭代对象
for i in soup.head.children:
    print("i:",i)

运行结果:

soup.head.contents: ['\n', <meta charset="utf-8"/>, '\n', <link href="css/style.min862f.css?v=4.1.0" rel="stylesheet"/>, '\n', <title>案例</title>, '\n']
soup.head.children: <list_iterator object at 0x000002233EEFD520>
i: 
i: <meta charset="utf-8"/>
i: 
i: <link href="css/style.min862f.css?v=4.1.0" rel="stylesheet"/>
i: 
i: <title>案例</title>
i: 
  • 获取孙节点

使用descendants属性获取子孙节点内容

        该属性返回一个generator对象,获取该对象中的所有内容,同样可以直接将其转换为list类型或者通过for循环遍历的方式进行获取。

<--myBook.html-->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <link href="css/style.min862f.css?v=4.1.0" rel="stylesheet">
    <title>案例</title>
</head>
<body class="fixed-sidebar full-height-layout gray-bg" style="overflow:hidden">
    <div id="wrapper">
        <p>段落1</p>
        <p>段落2</p>
    </div>
</body>
</html>

代码:
from bs4 import BeautifulSoup
html_str = open('myBook.html',mode='r',encoding='utf-8')
soup = BeautifulSoup(html_str,features='lxml')
descendants = soup.body.descendants
for i in descendants:
    print("i:",i)


运行结果:
i: 

i: <div id="wrapper">
<p>段落1</p>
<p>段落2</p>
</div>
i: 

i: <p>段落1</p>
i: 段落1
i: 

i: <p>段落2</p>
i: 段落2
i: 

i: 
  • 获取父节点

        获取父节点有两种方式:一种是通过parent属性直接获取指定节点的父节点内容,还可以通过parents属性获取指定节点的父节点及以上(祖先节点)内容,只是parents属性会返回一个generator对象,获取该对象的所有内容时,同样可以直接将其转换为list类型或者通过for循环的方式进行获取

from bs4 import BeautifulSoup
html_str = open('myBook.html',mode='r',encoding='utf-8')
soup = BeautifulSoup(html_str,features='lxml')
print('title.parent:',soup.title.parent)
print('title.parents:',soup.title.parents)
for i in soup.title.parents:
    print('i.name:',i.name)

运行结果:
title.parent: 
<head>
<meta charset="utf-8"/>
<link href="css/style.min862f.css?v=4.1.0" rel="stylesheet"/>
<title>案例</title>
</head>

title.parents: <generator object PageElement.parents at 0x0000019147DF6580>

i.name: head
i.name: html
i.name: [document]

  • 获取兄弟节点

<--myBook.html-->
<html>
<head>
    <title>关联获取演示</title>
    <meta charset="utf-8"/>
</head>
<body>
    <p class="p-1" value="1">
        <a href="https://item.jd.com/12353915.html">零基础学Python</a>
    </p>
    第一个p节点下文本
    <div class="div-1" value="2">
        <a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a>
    </div>
    <p class="p-3" value="3">
        <a href="https://item.jd.com/12512461.html">Python项目开发案例集锦</a>
    </p>
    <div class="div-2" value="4">
        <a href="https://item.jd.com/12550531.html">Python编程锦囊</a>
    </div>
</body>
</html>



from bs4 import BeautifulSoup
html_doc = open('myBook.html',mode='r',encoding='utf-8')
soup = BeautifulSoup(html_doc,features='lxml')
print('p.next_sibling:',soup.div.next_sibling)
div = soup.p.next_sibling.next_sibling
print("div:",div)

运行结果:
p.next_sibling: 
    第一个p节点下文本

div: <div class="div-1" value="2">
<a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a>
</div>

说明:

        如果标签与标签之间有换行,那么下一个节点获取到的就是空。比如获取第一个div节点的下一个节点获取到的就是空,下下一个节点才是p节点

1.4 使用find()方法获取

1.4.1 find_all()

from bs4 import BeautifulSoup
html_doc = """
<html>
<head>
    <title>关联获取演示</title>
    <meta charset="utf-8"/>
</head>

<body>
<p class="p-1" value = "1"><a href="https://item.jd.com/12353915.html">零基础学Python</a></p>
<p class="p-2" value = "2"><a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a></p>
<p class="p-3" value = "3"><a href="https://item.jd.com/12512461.html">Python项目开发案例集锦</a></p>
<div class="div-2" value = "4"><a href="https://item.jd.com/12550531.html">Python编程锦囊</a></div>
</body>
</html>
"""
soup = BeautifulSoup(html_doc,features='lxml')
print('所有p标签:',soup.find_all(name='p'))
print('第一个p标签的a标签:',soup.find_all(name='p')[0].find_all('a')[0])

运行结果:
所有p标签: [<p class="p-1" value="1"><a href="https://item.jd.com/12353915.html">零基础学Python</a></p>, <p class="p-2" value="2"><a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a></p>, <p class="p-3" value="3"><a href="https://item.jd.com/12512461.html">Python项目开发案例集锦</a></p>]

第一个p标签的a标签: <a href="https://item.jd.com/12353915.html">零基础学Python</a>

1.4.2 attrs参数

from bs4 import BeautifulSoup
html_doc = """
<html>
<head>
    <title>关联获取演示</title>
    <meta charset="utf-8"/>
</head>
<body>
<p class="p-1" value = "1"><a href="#">1</a></p>
<p class="p-1" value = "2"><a href="#">2</a></p>
<p class="p-3" value = "3"><a href="#">3</a></p>
<div class="div-2" value = "4"><a href="#">4</a></div>
</body>
</html>
"""

soup = BeautifulSoup(html_doc,features='lxml')
print('value=1的p标签:',soup.find_all('p',attrs={"value":1}))
print('value=1的所有标签:',soup.find_all(attrs={'value':1}))
print('打印class为p-1的所有内容:',soup.find_all(class_='p-1'))
print('打印value=3的内容:',soup.find_all(value='3'))

运行结果:
value=1的p标签: [<p class="p-1" value="1"><a href="#">1</a></p>]
value=1的所有标签: [<p class="p-1" value="1"><a href="#">1</a></p>]
打印class为p-1的所有内容: [<p class="p-1" value="1"><a href="#">1</a></p>, <p class="p-1" value="2"><a href="#">2</a></p>]
打印value=3的内容: [<p class="p-3" value="3"><a href="#">3</a></p>]

1.4.3 text参数

from bs4 import BeautifulSoup
import re
html_doc = """
<html>
<head>
    <title>关联获取演示</title>
    <meta charset="utf-8"/>
</head>
<body>
<p class="p-1" value = "1"><a href="#">Java</a></p>
<p class="p-1" value = "2"><a href="#">Python入门</a></p>
<p class="p-3" value = "3"><a href="#">C++</a></p>
<div class="div-2" value = "4"><a href="#">Vb</a></div>
</body>
</html>
"""
soup = BeautifulSoup(html_doc,features='lxml')
print('指定字符串锁获取的内容如下:',soup.find_all(text='Java'))
print('指定正则表达式对象锁获取的内容如下:',soup.find_all(text=re.compile('Python')))

运行结果:
指定字符串锁获取的内容如下: ['Java']
指定正则表达式对象锁获取的内容如下: ['Python入门']

1.4.4 find() 匹配第一个节点内容

from bs4 import BeautifulSoup
import re
html_doc = """
<html>
<head>
    <title>关联获取演示</title>
    <meta charset="utf-8"/>
</head>
<body>
<p class="p-1" value = "1" id="p1"><a href="#">零基础学Python</a></p>
<p class="p-2" value = "2" id="p2"><a href="#">Python从入门到项目实践</a></p>
<p class="p-3" value = "3" id="p3"><a href="#">Python项目开发案例集锦</a></p>
<p class="p-3" value = "4" id="p4"><a href="#">Python项目开发案例集锦</a></p>
<div class="div-2" value = "4"><a href="#">Python编程锦囊</a></div>
</body>
</html>
"""
soup = BeautifulSoup(html_doc,features='lxml')
print(soup.find(name='p'))
print(soup.find(class_='p-3'))
print(soup.find(attrs={'value':'4'}))
print(soup.find(text=re.compile('Python')))
print(soup.find('p',class_='p-3'))
print(soup.find('p',class_='p-3',value='3'))
print(soup.find('p',class_='p-3',id='p4'))

运行结果:
<p class="p-1" id="p1" value="1"><a href="#">零基础学Python</a></p>
<p class="p-3" id="p3" value="3"><a href="#">Python项目开发案例集锦</a></p>
<p class="p-3" id="p4" value="4"><a href="#">Python项目开发案例集锦</a></p>
零基础学Python
<p class="p-3" id="p3" value="3"><a href="#">Python项目开发案例集锦</a></p>
<p class="p-3" id="p3" value="3"><a href="#">Python项目开发案例集锦</a></p>
<p class="p-3" id="p4" value="4"><a href="#">Python项目开发案例集锦</a></p>

1.4.5 其他方法

根据条件获取节点内容的其他方法

方法名称

描述

find_parent()

获取父节点内容

find_parents()

获取所有祖先节点内容

find_next_sibling()

获取后面第一个兄弟节点内容

find_next_siblings()

获取后面所有兄弟节点内容

find_previous_sibling()

获取前面第一个兄弟节点内容

find_previous_siblings()

获取前面所有兄弟节点内容

find_next()

获取当前节点的下一个第一个符合条件的节点内容

find_all_next()

获取当前节点的下一个所有符合条件的节点内容

find_previous()

获取第一个符合条件的内容

find_all_previous()

获取所有符合条件的节点内容

1.4.6 CSS选择器

        Beautiful Soup模块还提供了CSS选择器来获取节点内容,如果Tag或者是BeautifulSoup对象都可以直接调用select()方法,然后填写指定参数即可通过CSS选择器获取到节点的内容。

在使用CSS选择器获取节点内容时,首先需要调用select()方法,然后为其指定字符串类型的CSS选择器。

常见的CSS选择器如下:

  • 直接填写字符串类型的节点名称
  • .class :表示指定class属性值
  • #id:表示指定id属性的值
from bs4 import BeautifulSoup  # 导入BeautifulSoup库
html_doc = """
<html>
<head>
    <title>关联获取演示</title>
    <meta charset="utf-8"/>
</head>
<body>
    <div class="test_1" id="class_1"> 
        <p class="p-1" value = "1"><a href="https://item.jd.com/12353915.html">零基础学Python</a></p>
        <p class="p-2" value = "2"><a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a></p>
        <p class="p-3" value = "3"><a href="https://item.jd.com/12512461.html">Python项目开发案例集锦</a></p>
        <p class="p-4" value = "4"><a href="https://item.jd.com/12550531.html">Python编程锦囊</a></p>
    </div>
    <div class="test_2" id="class_2">
        <p class="p-5"><a href="https://item.jd.com/12185501.html">零基础学Java(全彩版)</a></p>
        <p class="p-6"><a href="https://item.jd.com/12199033.html">零基础学Android(全彩版)</a></p>
        <p class="p-7"><a href="https://item.jd.com/12250414.html">零基础学C语言(全彩版)</a></p>
    </div>    
</body>
</html>
"""
soup = BeautifulSoup(html_doc,features='lxml')
print("所有p节点内容:",soup.select('p'))
print('所有p节点中的第二个p节点内容:',soup.select('p')[1])
print('类型为:test_2锁对应的节点',soup.select('.test_2'))
print('id值为class_1锁对应的节点:',soup.select('#class_1'))

运行结果:
1、所有p节点内容: [<p class="p-1" value="1"><a href="https://item.jd.com/12353915.html">零基础学Python</a></p>, <p class="p-2" value="2"><a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a></p>, <p class="p-3" value="3"><a href="https://item.jd.com/12512461.html">Python项目开发案例集锦</a></p>, <p class="p-4" value="4"><a href="https://item.jd.com/12550531.html">Python编程锦囊</a></p>, <p class="p-5"><a href="https://item.jd.com/12185501.html">零基础学Java(全彩版)</a></p>, <p class="p-6"><a href="https://item.jd.com/12199033.html">零基础学Android(全彩版)</a></p>, <p class="p-7"><a href="https://item.jd.com/12250414.html">零基础学C语言(全彩版)</a></p>]

2、所有p节点中的第二个p节点内容: <p class="p-2" value="2"><a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a></p>

3、类型为:test_2锁对应的节点 [<div class="test_2" id="class_2">
<p class="p-5"><a href="https://item.jd.com/12185501.html">零基础学Java(全彩版)</a></p>
<p class="p-6"><a href="https://item.jd.com/12199033.html">零基础学Android(全彩版)</a></p>
<p class="p-7"><a href="https://item.jd.com/12250414.html">零基础学C语言(全彩版)</a></p>
</div>]

4、id值为class_1锁对应的节点: [<div class="test_1" id="class_1">
<p class="p-1" value="1"><a href="https://item.jd.com/12353915.html">零基础学Python</a></p>
<p class="p-2" value="2"><a href="https://item.jd.com/12451724.html">Python从入门到项目实践</a></p>
<p class="p-3" value="3"><a href="https://item.jd.com/12512461.html">Python项目开发案例集锦</a></p>
<p class="p-4" value="4"><a href="https://item.jd.com/12550531.html">Python编程锦囊</a></p>
</div>]

根据条件获取节点内容的其他方法

获取节点内容方式

描述

soup.select('div[class="test_1"]')[0].select('p')[0]

嵌套获取class名为test_1对应的div中的所有p节点中的第一个

soup.select('p')[0]['value']

获取所有p节点中第一个节点内value属性对应的值(两种方法)

soup.select('p')[0].attrs['value']

soup.select('p')[0].get_text()

获取所以p节点中第一个节点内的文本

soup.select('p')[0].string

soup.select('p')[1:]

获取所有p节点中第二个以后的p节点

soup.select('.p-1,.p-5')

获取class名为p-1与p-5对应的节点

soup.select('a[href]')

获取存在href属性的所有a节点

soup.select('p[value="1"]')

获取所有属性值为value='1'的p节点

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小马哥-码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值