Python3编写网络爬虫06-基本解析库Beautiful Soup的使用
二、Beautiful Soup
简介 就是python的一个HTML或XML的解析库 可以用它来很方便的从网页中提取数据
0.1 提供一些简单的 python式的函数来处理导航,搜索,修改分析树等功能,
它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用
0.2 自动将输入的文档转换为Unicode编码,输出文档转换为UTF-8编码,不需要考虑编码方式,
除非文档没有指定一个编码方式,这是你仅仅需要说明以下原始编码格式就可以了。
0.3 已成为和lxml,html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。
安装 Beautiful Soup 解析器依赖lxml库 保证lxml库安装
pip install beautifulsoup4
验证:
from bs4 import BeautifulSoup soup = BeautifulSoup('<p>Hello</p>','lxml')
print(soup.p.string) #输出Hello
1.解析器
BeautifulSoup在解析的时候 依赖解析器 除了支持python标准库HTML解析器之外 还支持第三方解析器(lxml)
例如
解析器 优势 劣势
python标准库 python内置标准库 执行速度适中, python2.7.3及python3.2.2之前的版本 文档容错率差
文档容错能力强
lxml HTML解析器 速度快 文档容错能力强 需要安装C语言库
lxml XML解析器 速度快 唯一支持XML的解析器 需要安装C语言库
html5lib 最好的容错性,以浏览器的方式解析文档 速度慢 不依赖外部拓展
生成HTML5格式文档
对比可以看出lxml解析器有解析HTML和XML的功能 速度快 容错能力强
使用时 将第二个参数改为lxml
2.基本用法
html='''
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dormouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their name were
<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>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
''' from bs4 import BeautifulSoup soup = BeautifulSoup(html,'lxml')#初始化
print(soup.prettify())#把要解析的字符串以标准的缩进格式输出
print(soup.title.string)#输出HTML中title节点的文本内容
3.节点选择器
直接调用节点的名字就可以选择节点元素,再调用string属性就可以得到节点内的文本,
这种选择方式速度非常快,如果单个节点结构层次清晰可以选用这种方式
3.1 选择元素
html='''
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dormouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their name were
<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>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
''' from bs4 import BeautifulSoup soup = BeautifulSoup(html,'lxml') print(soup.title)#获取title节点 print(type(soup.title))#打印类型为bs4.element.Tag类型 经过选择器选择后 结果都是这种Tag类型 print(soup.title.string)#调用Tag里的string属性 得到节点的文本内容 print(soup.head)#查找heda节点 print(soup.p)#查找p节点 结果只有一个 后面的没有选到 这种方式只会选择到第一个匹配的节点
3.2 提取信息
获取节点名称
可以利用name属性获取节点名称 选取title节点 调用name属性
print(soup.title.name)
获取属性
每个节点可能有多个属性 比如 id class ... 选择这个节点元素后,可以调用attrs获取所有属性
print(soup.p.attrs)#返回结果是字典形式
# 获取字典里面某个键值 只需要中括号加属性名
print(soup.p.attrs['name'])
更简单的获取方式
print(soup.p['name'])#返回结果是字符串
print(soup.p['class'])#返回结果是列表 实际处理时要注意类型
3.3获取内容
print(soup.p.string)#返回结果是第一个p节点的文本内容
3.4 嵌套选择
html='''
<html><head><title>The Dormouse's story</title></head>
<body>
'''
from bs4 import BeautifulSoup soup = BeautifulSoup(html,'lxml')
print(soup.head.title)#title节点元素
print(type(soup.head.title))#打印类型为Tag 在Tag基础上再次选择得到的依然是Tag
print(soup.head.title.string)#输出string属性 获取文本内容
3.5关联选择
子节点和子孙节点
html='''
<html>
<head>
<title>The Dormouse's story</title>
</head>
<body>
<p class="story">
Once upon a time there were three litile sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">
<span>Elsie</span>
</a>
<a href="http://example/lacie" class="sister" id="link2">Lacie</a>
and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
and they lived at the bottom of a well.
</p>
<p class="story">...</p>
''' soup = BeautifulSoup(html,'lxml')
print(soup.p.contents)
结果是列表形式 p节点里包含文本 又包含节点
注意:列表中的每个元素都是p节点的直接子节点 例如span 相当于p节点的子孙节点 但是结果没有单独选出来
contents 返回直接子节点的列表
也可以使用children属性
print(soup.p.children)#返回结果是迭代器 for i,child in enumerate(soup.p.children):
print(i,child)#遍历
descendants 子孙节点
print(soup.p.descendants)#返回结果是生成器 for i,child in enumerate(soup.p.descendants):
print(i,child)#遍历 得到所有子孙节点
父节点和祖先节点
获取某个节点的父节点 可以调用parent属性
print(soup.a.parent)#返回p节点及其内部内容 获取某个节点的祖先节点 可以调用parents属性 print(soup.a.parents)#返回生成器 print(list(enumerate(soup.a.parents)))#列表输出索引和内容 列表中的元素就是a标签的祖先节点
兄弟节点
html = '''
<html>
<body>
<p class="story">
Once
<a href="www.baidu.com">
<span>Elsie</span>
</a>
Hello
<a href="www.baidu2.com">Lacie</a>
and
<a href="www.baidu3.com">Tillie</a>
and they
</p>
'''
soup = BeautifulSoup(html,'lxml') print('Next Sibling',soup.a.next_sibling)#获取节点的下一个兄弟元素
print('Prev Sibling',soup.a.previous_sibling)#获取节点的上一个兄弟元素
print('Next Siblings',list(enumerate(soup.a.next_siblings)))#获取后面的兄弟节点
print('Prev Siblings',list(enumerate(soup.a.previous_siblings)))#获取前面的兄弟节点
提取信息
示例:
html='''
<html>
<body>
<p class="story">
Once upon...; and their
<a href="www.baidu.com" class="sister" id="link1">Bod</a><a href="www.baidu2.com"
class="sister" id="link2">Lacie</a>
</p>
''' soup = BeautifulSoup(html,'lxml') print('Next Sibling:')
print(type(soup.a.next_sibling))
print(soup.a.next_sibling)
print(soup.a.next_sibling.string)
print('Parent:')
print(type(soup.a.parents))
print(list(soup.a.parents)[0])
print(list(soup.a.parents)[0].attrs['class'])
如果返回的是单个节点,可以直接调用string attrs等属性获取文本和属性
如果返回的是多个节点,可以转为列表后取出某个元素再调用string attrs获取对应节点的文本和属性
4.方法选择器
find_all() #查询所有符合条件的元素
find_all(name,attrs,recursive,text,**kwargs)
4.1 name #根据节点名查询元素
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>
''' soup = BeautifulSoup(html,'lxml') print(soup.find_all(name="ul"))#查找所有ul节点
print(type(soup.find_all(name="ul")[0]))#类型为Tag类型
查询其内部的li节点
for ul in soup.find_all(name="ul"):
print(ul.find_all(name="li"))
遍历每个li 获取文本内容
for ul in soup.find_all(name="ul"):
print(ul.find_all(name="li"))
for li in ul.find_all(name="li"):
print(li.string)
4.2 attrs #根据属性查询
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1" name="elements">
<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>
'''
soup = BeautifulSoup(html,'lxml') print(soup.find_all(attrs={'id':'list-1'}))#结果为列表形式
print(soup.find_all(attrs={'name':'elements'}))
简写方式
print(soup.find_all(id="list-1"))#返回id 为list-1的节点元素
print(soup.find_all(class_="element"))#由于class在python中是关键字 所以加 _ 结果依然是Tag类型的列表
4.3 text #匹配节点中的文本 可以是字符串 也可以是正则表达式
import re html='''
<div class="panel">
<div class="panel-body">
<a>Hello,this is a link</a>
<a>Hello,this is a link,too</a>
</div>
</div>
''' soup = BeautifulSoup(html,'lxml') print(soup.find_all(text=re.compile('link')))#返回正则表达式匹配的节点文本 组成的列表
4.4 find() #查询符合条件的第一个元素 返回单个元素
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" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
</ul>
</div>
</div>
''' soup = BeautifulSoup(html,'lxml') print(soup.find(name="ul"))
print(type(soup.find(name="ul")))
print(soup.find(class_="list"))
# 返回结果不再是列表形式 只有第一个匹配元素 类型依然是Tag类型
更多查询方法 用法相同 范围不同
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() :前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点
5.CSS选择器
使用css选择器 需要调用 select()方法 传入相应的css选择器
示例:
html='''
<div class="panel">
<div class="panel-heading">
<h4>Hello</h4>
</div>
<div class="panel-body">
<ul class="list" id="list-1" name="elements">
<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>
''' soup = BeautifulSoup(html,'lxml') print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))#类型依然是Tag类型
5.1 嵌套选择
示例:
soup = BeautifulSoup(html,'lxml') for ul in soup.select('ul'):
print(ul.select('li'))#返回ul下 所有li组成的列表
5.2 获取属性
示例:获取所有ul节点的id属性
for ul in soup.select('ul'):
print(ul['id'])
print(ul.attrs['id'])
5.3 获取文本
可以选择用string 或者 get_text()
for li in soup.select('li'):
print('Get Text:',li.get_text())
print('String',li.string)
#效果完全相同
总结: 推荐使用lxml解析库 必要时使用html.parser
节点选择筛选功能弱但是速度快
建议使用 find() 或者 find_all() 查询匹配单个结果或者多个结果
如果对CSS选择器熟悉 可以使用 select() 方法选择
Python3编写网络爬虫06-基本解析库Beautiful Soup的使用的更多相关文章
- Python3编写网络爬虫05-基本解析库XPath的使用
一.XPath 全称 XML Path Language 是一门在XML文档中 查找信息的语言 最初是用来搜寻XML文档的 但是它同样适用于HTML文档的搜索 XPath 的选择功能十分强大,它提供了 ...
- Python3编写网络爬虫07-基本解析库pyquery的使用
三.pyquery 简介:同样是一个强大的网页解析工具 它提供了和jQuery类似的语法来解析HTML文档,支持CSS选择器,使用非常方便 安装: pip install pyquery 验证: im ...
- Python3编写网络爬虫02-基本请求库requests的使用
一.requests 库使用 需要安装 pip install requests import requests #导入requests库 request = requests.get("h ...
- Python3编写网络爬虫01-基本请求库urllib的使用
安装python后 自带urllib库 模块篇 分为几个模块如下: 1. urllib.request 请求模块 2. urllib.parse 分析模块 3. urllib.error 异常处理模块 ...
- 小白学 Python 爬虫(21):解析库 Beautiful Soup(上)
小白学 Python 爬虫(21):解析库 Beautiful Soup(上) 人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前 ...
- 小白学 Python 爬虫(22):解析库 Beautiful Soup(下)
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- python3编写网络爬虫20-pyspider框架的使用
二.pyspider框架的使用 简介 pyspider是由国人binux 编写的强大的网络爬虫系统 github地址 : https://github.com/binux/pyspider 官方文档 ...
- python3编写网络爬虫21-scrapy框架的使用
一.scrapy框架的使用 前面我们讲了pyspider 它可以快速的完成爬虫的编写 不过pyspider也有一些缺点 例如可配置化不高 异常处理能力有限对于一些反爬虫程度非常强的网站 爬取显得力不从 ...
- Python3编写网络爬虫08-数据存储方式一-文件存储
数据存储 用解析器解析出数据之后,就是存储数据了.保存的形式可以多种多样,最简单的形式是直接保存为文本文件,如TXT JSON CSV等.另外还可以保存到数据库中,如关系型数据库MySQL 非关系型数 ...
随机推荐
- SpringBoot2.0源码分析(一):SpringBoot简单分析
SpringBoot2.0简单介绍:SpringBoot2.0应用(一):SpringBoot2.0简单介绍 本系列将从源码角度谈谈SpringBoot2.0. 先来看一个简单的例子 @SpringB ...
- Android中不能在子线程中更新View视图的原因
这是一条规律,很多coder知道,但原因是什么呢? 如下: When a process is created for your application, its main thread is ded ...
- 自己动手实现java数据结构(八) 优先级队列
1.优先级队列介绍 1.1 优先级队列 有时在调度任务时,我们会想要先处理优先级更高的任务.例如,对于同一个柜台,在决定队列中下一个服务的用户时,总是倾向于优先服务VIP用户,而让普通用户等待,即使普 ...
- #6 Python数据类型及运算
前言 前文讲述了Python的输入输出以及变量的相关知识点,本节将探讨Python的数据类型以及数据之间的运算方式! 一.Python数据类型 上一节弄清了变量,其实变量所指向的值是有自己独特的数据类 ...
- 如何参与linux内核开发
如何参与linux 内核开发 如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维 ...
- 源码编译安装MySQL8.0
源码编译安装MySQL8.0 0.前期准备条件 查看linux的版本 [root@mysql etc]# cat /etc/redhat-release CentOS Linux release 7. ...
- python字典操作和内置方法
一 字典基本介绍 python中只有字典是映射结构,通过key取值,并且key是不可变数据类型,而value可以是任意数据类型. 字典通过一个花括号,里面存放key:value的数据结构来定义.理论上 ...
- [转]微擎MVC
本文转自:https://www.kancloud.cn/donknap/we7/134626 控制器 控制器以文件夹.文件的形式组织,位于系统的 source 目录下,每一个目录代表一个 contr ...
- jQuery中的事件绑定的几种方式
jQuery目前有on(),bind(),delegate(),live()四种绑定方式,但是随着版本的不断更新,有的方式也相应的被淘汰掉 [band()方式绑定] 3.0版本之前的绑定方式比较常用的 ...
- makefile中":=","=","?=","+="
= 无关位置的等于,值永远等于最后的值 比如: x =a y =$(x) x =b 那么y的值永远等于最后的值,等于 b ,而不是a := 有关位置的等于,值取决于当时位置的值 比如: ...