『第二周』BeautifulSoup库
文章目录
Beautiful Soup库
帮助文档:https://beautifulsoup.readthedocs.io/zh_CN/latest/
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的第三方库,需要安装。
pip install beautifulsoup4
Beautiful Soup库,简称bs4,是解析、遍历、维护“标签树”的功能库。
解析器及其区别
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
python标准库 | BeautifulSoup(markup, "html.parser") | * python的内置标准库 * 执行速度适中 * 文档容错能力强 | * python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, "lxml") | * 速度快 * 文档容错能力强 | * 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, ["lxml-xml"])<br> BeautifulSoup(markup, "xml") | * 速度快 * 唯一支持XML的解析器 | * 需要安装C语言库 |
html5lib | BeautifulSoup(markup, "html5lib") | * 最好的容错性 * 以浏览器的方式解析文档 * 生成HTML5格式的文档 | * 速度慢 * 不依赖外部扩展 |
推荐使用lxml作为解析器,因为效率更高。
几种解析器的区别
如果一个格式完美(perfectly-formed)的html,使用不同的解析器没什么区别。
但如果不是格式完美,则不同的解析器会给出不同的结果。
>>> BeautifulSoup("<a></p>", "lxml")
<html><body><a></a></body></html>
>>> BeautifulSoup("<a></p>", "html5lib")
<html><head></head><body><a><p></p></a></body></html>
>>> BeautifulSoup("<a></p>", "html.parser")
<a></a>
BeautifulSoup基本元素
基本元素 | 说明 |
---|---|
Tag | 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾 |
Name | 标签的名字,<p>...</p> 的名字是’p’,格式:<tag>.name |
Attributes | 标签的属性,字典形式组织,格式: <tag>.attrs |
Navigablestring | 标签内非属性字符串,<>...</> 中字符串,格式:<tag>.string |
Comment | 标签内字符串的注释部分,一种特殊的Comment类型 |
解析树型结构
下行遍历:
属性 | 说明 |
---|---|
.contents | 子节点的列表,将所有儿子节点存入列表 |
.children | 子节点的迭代类型,与.contents类似,用于循环遍历 |
.descendants | 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历 |
>>> soup.head.contents
[<title>This is a python demo page</title>]
for child in soup.body.children:
print(child) ##遍历儿子节点
for child in soup.body.descendants:
print(child) ##遍历子孙节点
上行遍历:
属性 | 说明 |
---|---|
.parent | 节点的父亲标签 |
.parents | 节点先辈标签的迭代类型,用于循环遍历先辈节点 |
>>>soup.title.parent
<head><title>This is a python demo page</title></head>
>>> for parent in soup.a.parents:
if parent is None:
print(parent)
else:
print(parent.name)
P
body
html
[document]
## 遍历所有先辈节点,包括soup本身,所以要区别判断
平行遍历:
属性 | 说明 |
---|---|
.next_sibling | 返回按照HTML文本顺序的下一个平行节点标签 |
.previous_sibling | 返回按照HTML文本顺序的上一个平行节点标签 |
.next_siblings | 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签 |
previous_siblings | 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签 |
>>> soup.a.next_sibling
'and'
for sibling in soup.a.next_siblings:
print(sibling) ## 遍历后续节点
for sibling in soup.a.previous_siblings:
print(sibling) ## 遍历前续节点
如何更优雅的显示HTML页面?
.prettify()为HTML文本及其内容增加’\n’,可用于标签,方法:<tag>.prettify()
bs4库将任何HTML输入都变成utf-8编码,而python 3.x默认支持编码是utf-8,解析无障碍。
>>> soup.p
<p class="title"><b>The demo python introduces several python courses.</b></p>
>>> soup.p.prettify()
'<p class="title">\n <b>\n The demo python introduces several python courses.\n </b>\n</p>\n'
>>> print(soup.p.prettify())
<p class="title">
<b>
The demo python introduces several python courses.
</b>
</p>
信息标记
XML eXtensible Markup Language
<name>...</name>
<name />
<!---->
JSON JavaScript Object Notation
有类型的键值对 key : value
"key": "value"
"key": ["value1", "value2"]
"key": {"subkey": "subvalue"}
YAML YAML Ain’t Markup Language
无类型键值对key:value
key: value
key: ##Comment
-value1
-value2
key:
subkey: subvalue
三种信息标记形式的比较
XML | 最早的通用信息标记语言,可扩展性好,但繁琐。 | Internet上的信息交互与传递。 |
JSON | 信息有类型,适合程序处理(js),较XML简洁。 | 移动应用云端和节点的信息通信,无注释。 |
YAML | 信息无类型,文本信息比例最高,可读性好。 | 各类系统的配置文件,有注释易读。 |
信息提取的一般方法
方法 | 形式 | 需求 | 优点 | 缺点 |
---|---|---|---|---|
完整解析信息的标记形式,再提取关键信息 | XML JSON YAML | 需要标记解析器,例如:bs4库的标签树遍历 | 信息解析准确 | 提取过程繁琐,速度慢 |
无视标记形式,直接搜索关键信息 | 搜索 | 对信息的文本查找函数即可 | 提取过程简洁,速度较快 | 提取结果准确性与信息内容相关 |
结合形式解析与搜索方法,提取关键信息 | XML JSON YAML +搜索 | 需要标记解析器及文本查找函数 |
<>.find_all(name, attrs, reccursive, string, **kwargs)
返回一个列表,存储查找的结果
-
name: 对标签名称的检索字符串
-
attrs: 对标签属性值的检索字符串,可标注属性检索
-
recursive: 是否对子孙全部检索,默认True
-
string: <>…</>中字符串区域的检索字符串
<tag>(..) 等价于 <tag>.find_all(..)
扩展方法
方法 | 说明 |
---|---|
<>.find() | 搜索且只返回一个结果,同.find_all()参数 |
<>.find_parents() | 在先辈节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_parent() | 在先辈节点中返回一个结果,同.find()参数 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_next_sibling() | 在后续平行节点中返回一个结果,同.find()参数 |
<>.find_previous_siblings() | 在前序平行节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_previous_sibling() | 在前序平行节点中返回一个结果,同.find()参数 |
.string和.text
.string方法在tag包含多个子节点时,tag无法确定.string方法应该调用哪个子节点的内容,所以输出None
.text可以返回当前节点所包含的所有文本内容,包括当前节点的子孙节点
.format中文对齐
问题
原理
因为单个西文字符的长度要比单个中文字符的长度要小,所以当所需的中文字符串长度大于所提供的长度时,便会自动占用后面的空间,导致后面数据的排版不符合我们的规定。
解决
将空格转化为中文空格
print("{:^5}\t{:{}^20}\t{:^5}".format("排名", "大学", chr(12288), "总分"))
结果
扩展
[1] 陌上行走.python3中eval函数用法简介.https://blog.youkuaiyun.com/qq_29883591/article/details/53443062
[2] 牧歌_.深入解析Python中的__builtins__内建对象.https://www.jb51.net/article/87076.htm