您的位置:首页 > 理论基础 > 计算机网络

Python网络爬虫与信息提取(二)—— BeautifulSoup

2017-09-30 18:45 786 查看
BeautifulSoup官方介绍:

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.

官方网站:https://www.crummy.com/software/BeautifulSoup/

BeautifulSoup安装

在"C:\Windows\System32"中找到"cmd.exe",使用管理员身份运行,在命令行中输入:“pip install beautifulsoup4”运行。

C:\Windows\system32>pip install beautifulsoup4
Requirement already satisfied (use --upgrade to upgrade): beautifulsoup4 in c:\users\lei\appdata\local\programs\python\p
ython35\lib\site-packages\beautifulsoup4-4.5.0-py3.5.egg
You are using pip version 8.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.


提示pip版本过低,使用
python -m pip install --upgrade pip
进行升级。

Beautiful Soup库的安装测试:

from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data</p>','html.parser')


演示HTML页面地址:http://www.cnblogs.com/yan-lei

>>> import requests
>>> from bs4 import BeautifulSoup
>>> r = requests.get("http://www.cnblogs.com/yan-lei/")
>>> demo = r.text
>>> soup = BeautifulSoup(demo,"html.parser")
>>> soup


Beautiful Soup库的使用

以HTML为例,任何HTML文件都是有一组"<>"组织起来的,其实就是标签,标签之间形成了上下游关系,形成了标签树。BeautifulSoup库是解析、遍历、维护“标签树”的功能库

<p>..</p>:标签Tag

标签Name一般成对出现

属性Attributes 0个或多个

Beautiful Soup库的引用

Beautiful Soup库,也叫beautfulsoup4 或bs4。约定引用方式如下,即主要是用BeautifulSoup类。

from bs4 import BeautifulSoup
import bs4


Beautiful Soup类

将标签树转换为BeautifulSoup类,此时我们将HTML、标签树、BeautifulSoup类等价

from bs4 import BeautifulSoup
soup1 = BeautifulSoup("<html>data</html>","html.parser")
soup2 = BeautifulSoup(open("D://demo.html",'rb'),"html.parser")


使用
soup2 = BeautifulSoup(open("D://demo.html"),"html.parser")
报错:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\lei\AppData\Local\Programs\Python\Python35\lib\site-packages\beautifulsoup4-4.5.0-py3.5.egg\bs4\__init_
_.py", line 191, in __init__
UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 2: illegal multibyte sequence


BeautifulSoup对应一个HTML/XML文档的全部内容。

Beautiful Soup库解析器

解析器使用方法条件
bs4的HTML解析器BeautifulSoup(mk,'html.parser')安装bs4库
lxml的HTML解析器BeautifulSoup(mk,'lxml')pip install lxml
lxml的XML解析器BeautifulSoup(mk,'xml')pip install lxml
html5lib的解析器BeautifulSoup(mk,'html5lib')pip install html5lib

Beautiful Soup类的基本元素

基本元素说明
Tag标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾
Name标签的名字,<p>...</p>的名字是'p',格式:<tag>.name
Attributes标签的属性,字典形式的组织,格式:<tag>.attrs
NavigleString标签内非属性字符串,<>...</>中字符串,格式<tag>.string
Comment标签内字符串的注释部分,一种特殊的Comment类型
Tag标签:任何存在于HTML语法中的标签都可以用soup.<tag>访问获得;当HTML文档中存在多个相同<tag>对应内容时,soup.<tag>返回第一个。

Tag的名字(name):每个<tag>都有自己的名字,通过<tag>.name获取,字符串类型。

Tag的attrs(属性):一个<tag>可以有0个或多个属性,字典类型。

Tag的NavigableString:NavigableString可以跨越多个层次

Tag的Comment:Comment是一种特殊类型。

>>> import requests
>>> from bs4 import BeautifulSoup
>>> r = requests.get('http://www.cnblogs.com/yan-lei/')
>>> html = r.text
>>> soup = BeautifulSoup(html,'html.parser')
>>> soup.title
<title>Python学习者 - 博客园</title>
>>> soup.a
<a name="top"></a>
>>> soup.a.name
'a'
>>> soup.a.parent.name
'body'
>>> soup.a.attrs
{'name': 'top'}
>>> type(soup.a)
<class 'bs4.element.Tag'>
>>> type(soup.a.attrs)
<class 'dict'>
>>> soup.h1.string
'Python学习者'
>>> type(soup.h1.string)
<class 'bs4.element.NavigableString'>


基于bs4库的HTML内容遍历方法

HTML中 <...>构成了所属关系,形成了标签的树形结构,有三种遍历方式。

使用以下的HTML进行测试:E:\BeautifulSoupTest.html

<html>
<head>
<meta charset="utf-8">
<title>BeautifulSoup</title>
</head>
<body>
<div id="header">
<h1  style="font-size:16px;text-align:center">这里是标题</h1>
</div>
<div id="nav">
<h1>左导航</h1>
</div>
<div id="main">
<p>第一段</p>
<p>第二段</p>
<img src="test.jpg"/>
<p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>

</div>
<div id="footer">
<h1>底边</h1>
</div>

</body>
</html>


标签树的下行遍历

属性说明
.contents子节点的列表,将<tag>所有儿子节点存入列表
.contents子节点的列表,将<tag>所有儿子节点存入列表
.children子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
BeautifulSoup类是标签树的根节点

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(open('E:\\BeautifulSoupTest.html','rb'),'html.parser')
>>> soup.head.contents #返回的是列表
['\n', <meta charset="utf-8">
<title>BeautifulSoup</title>
</meta>]
>>> len(soup.body.contents)
9
>>> for child in soup.body.children:   # 遍历儿子节点
...     print(child)
...

<div id="header">
<h1 style="font-size:16px;text-align:center">这里是标题</h1>
</div>

<div id="nav">
<h1>左导航</h1>
</div>

<div id="main">
<p>第一段</p>
<p>第二段</p>
<img src="test.jpg">
<p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
</img></div>

<div id="footer">
<h1>底边</h1>
</div>

>>> for child in soup.body.descendants:  # 遍历子孙节点
...     print(child)
...

<div id="header">
<h1 style="font-size:16px;text-align:center">这里是标题</h1>
</div>

<h1 style="font-size:16px;text-align:center">这里是标题</h1>
这里是标题

<div id="nav">
<h1>左导航</h1>
</div>

<h1>左导航</h1>
左导航

<div id="main">
<p>第一段</p>
<p>第二段</p>
<img src="test.jpg">
<p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
</img></div>

<p>第一段</p>
第一段

<p>第二段</p>
第二段

<img src="test.jpg">
<p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
</img>

<p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
<a href="http://www.cnblogs.com/yan-lei/">博客园</a>
博客园

<div id="footer">
<h1>底边</h1>
</div>

<h1>底边</h1>
底边


for child in soup.body.children:   # 遍历儿子节点
print(child)

for child in soup.body.descendants:  # 遍历子孙节点
print(child)


标签树的上行遍历

属性说明
.parent节点的父亲标签
.parents节点先辈标签的迭代类型,用于循环遍历先辈节点
>>> for parent in soup.a.parents:
...     if parent is None:
...             print(parent)
...     else:
...             print(parent.name)
...
p
img
div
body
html
[document]


# 判断所有先辈节点,包括soup本身,所以要区别判断
for parent in soup.a.parents:
if parent is None:
print(parent)
else:
print(parent.name)


标签树的平行遍历

属性说明
.next_sibling返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling返回按照HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签
*所有的平行遍历发生在同一个父节点下的各节点间。

# div标签下一个平行节点标签
soup.div.next_sibling

# div标签上一个平行节点标签
soup.div.previous_sibling

# 遍历后续节点
for sibling in soup.div.next_sibling:
print(sibling)

# 遍历前续节点
for sibling in soup.div.previous_sibling:
print(sibling)


基于bs4库的HTML格式输出

bs4库的prettify()方法

.prettify()为HTML文本<>及其内容增加'\n'

.prettify()可用于标签,方法:<tag>.prettify()

print(soup.prettify())


bs4库将任何HTML输入都变成utf-8编码,Python 3.x默认支持编码是utf-8,解析无障碍。

信息标记的三种形式

信息的标记:

标记后的信息可形成信息组织结构,增加了信息维度

标记后的信息可用于通信、存储或展示

标记的结构与信息一样具有重要价值

标记后的信息更利于程序的理解和运用

HTML的信息标记:

HTML是WWW(World Wide Web)的信息组织方式。

HTML通过预定义的<>...</>标签形式组织不同类型的信息。

XML eXtensible Markup Language

XML格式是基于HTML格式发展以来的一种通用的信息格式。

XML基本格式:<name> ... </name>

空元素缩写形式:<name />

注释书写形式:<!-- -->

JSON JavaScript Object Notation

有类型的键值对 key:value

使用 "" 表达是字符串类型,没有字符串则是数字类型。

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库的标签树遍历

优点:信息解析准确

缺点:提取过程繁琐,速度慢。

方法二:无视标记形式,直接搜索关键信息。

搜索

对信息的文本查找函数即可。

优点:提取过程简介,速度较快。

缺点:提取结果准确性与信息内容相关。

方法三:融合方法

融合方法:结合形式解析与搜索方法,提取关键信息。

基于bs4库的HTML内容查找方法

<>.find_all(name,attrs,recursive,string,**kwargs)

返回一个列表类型,存储查找结果。

name:对标签名称的检索字符串。

attrs:对标签属性值的检索字符串,可标注属性检索。

recursive:是否对子孙全部检索,默认True。

string:<>...</>中字符串区域的检索字符串。

<tag>(..) 等价于 <tag>.find_all(..)

soup(..) 等价于 soup.find_all(..)

>>> soup.div()
[<h1 style="font-size:16px;text-align:center">这里是标题</h1>]
>>> for tag in soup.find_all(True):  # 返回所有的标签
...     print(tag.name)
...
html
head
meta
title
body
div
h1
div
h1
div
p
p
img
p
a
div
h1


扩展方法

方法说明
<>.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()参数


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: