Python网络爬虫与信息提取笔记04-Beautiful Soup库入门

Python网络爬虫与信息提取笔记01-Requests库入门

Python网络爬虫与信息提取笔记02-网络爬虫之“盗亦有道"

Python网络爬虫与信息提取笔记03-Requests库网络爬虫实战(5个实例)


本文索引:

  1. BeautifulSoup库的安装
  2. BeautifulSoup库的基本元素
  3. 基于bs4库的HTML内容遍历方法
  4. 基于bs4库的HTML格式化和编码 

1、Beautiful Soup库安装

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。

安装只有一步,我们使用管理员权限打开cmd,输入下面这串代码

pip install beautifulsoup4

这样就算完成了。

下面我们测试一下库的安装,演示HTML页面地址:https://python123.io/ws/demo.html

1、我们打开这个页面,是这样的,然后鼠标右键打开网页源代码

2、那么我们之前学到的requests库的get方法,就可以获取这个网页的源代码,那么我们结合requests库和新安装的BeautifulSoup库来试一下。首先打开IDLE,导入requests库,获取到这个hyml页面的源代码内容

3、接着我们先将这个代码内容赋给变量demo,然后导入BeautifulSoup库,导入使用语句是

from bs4 import BeautifulSoup

然后使用一个soup变量,对刚才的demo变量进行解析处理,其中使用的html参数parser,就是用来解析格式的。最后输出美化后的代码:

我们看到输出的页面是已经处理过的,这说明我们的BeautigulSoup库也安装成功了。

其实其中最关键的就是这两行代码:

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

第一行为导入库,第二行中的连个参数分别是:

  • <p>data</p>:表示需要解析的html格式的信息,也可先将其付给一个变量,再传进来
  • html.parser:这个是要解析html格式所需的解析器。

2、BeatifulSoup库的基本元素

  • 对Beautiful Soup库的理解

我们知道,html是一组尖括号<>组织起来的一组标签所组成的内容,标签之间存在上下游关系,形成一个所谓的“标签树”,像上面那样的html内容,所以我们可以理解Beautiful Soup库是解析、遍历、维护“标签树”的功能库。

  • Beautiful Soup库的引用

一般情况下,我们最常使用的是from bs4 import BeautifulSoup,这一种说明是我们从bs4库中引入一个类,叫BeautifulSoup,注意这里B和S大写。

我们怎么理解Beautiful Soup类呢?

一般的这个类用来解析的html或者xml的文档,这个文档与标签树是一一对应的,经过BeautifulSoup库的转换,我么就可以理解为将其转换成了一个Beautiful Soup类,这个Beautiful Soup类就可以代替这个标签树,

  • 前面我们提到了HTML解析器,其实beautifulsoup还提供了另外4种解析器
解析器 使用方法 条件
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
NavigableString 标签内非属性字符串,<>...</>中字符串,格式:<tag>.string
Comment 标签内字符串的注释部分,一种特殊的Comment类型

为了更好的理解Beautiful Soup类的基本元素,我们来回顾一下前面的demo实例:

有一个demo示例页面:http://python123.io/ws/demo.html,通过下面这行代码我们可以获得页面的内容,并将其赋值给demo变量。

>>> import requests
>>> r = requests.get("http://python123.io/ws/demo.html")
>>> r.status_code
200
>>> r.text
'<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>\r\n</body></html>'
>>> demo = r.text

1、下面我们说一下获得tag标签的方法,代码如下:

这时,soup变量表示的内容是解析后的demo界面,这时打印出的title界面就是我们浏览器左上方显示信息的地方,这个标签表示的就是那个位置的信息的内容,

下面我们来获取html中.a标签即链接标签的内容,并将其打印(soup.tag返回html文本中第一个标签):

2、获取标签名字的方法

我们不在赘述前面demo变量的定义,直接给出获取标签名字的代码,其中.parent.name是获取标签上一级标签的名称

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(demo,"html.parser")
>>> soup.a.name
'a'
>>> soup.a.parent.name
'p'
>>> soup.a.parent.parent.name
'body'
>>> 

3、获取标签的属性

我们可以接着上面的代码接着写,直接获取属性的值:

>>> tag = soup.a
>>> tag.attrs
{'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'}
>>> tag.attrs['class']
['py1']
>>> type(tag.attrs)
<class 'dict'>
>>> type(tag)
<class 'bs4.element.Tag'>
>>> 

这里,我们可以查看标签属性的类型是字典,标签的类型是标签类型,tag.attrs是直接返回整个字典,我们也可以用tag.attrs['class']查看其中属性为键为class的属性值,注意tag标签的属性有0或多个类型,但总能返回一个字典来表示。

4、NavigableString元素

它表示的是标签<>...</>中的字符串信息,我们来查看一下各个标签中的字符串信息:

我们可以看到,各个标签<>之间的内容,如soup.a.string表示的就是<a>...<a>之间的内容,但不包括其他的标签名称,比如我们发现soup.p.string返回的内容并不包括其<>...<>中间的<b>内容,既可以跨越多个标签层次。

5、Comment元素

表示标签内注释的部分,我们查看这段注释的内容和类型,代码如下(注意,格式里面的!--..--被去掉了):

>>> newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>","html.parser")
>>> newsoup.b.string
'This is a comment'
>>> type(newsoup.b.string)
<class 'bs4.element.Comment'>
>>> type(newsoup.p.string)
<class 'bs4.element.NavigableString'>
>>> 

这里面的5种元素只是BeautifulSoup库的基本使用,后面的实际案例中会更多的使用。

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

首先我们来回顾一下之前所示例的那个demo实例,因为我们要频繁使用这个例子。

>>> import requests
>>> r = requests.get("http://python123.io/ws/demo.html")
>>> r.status_code
200
>>> r.text
'<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>\r\n</body></html>'
>>> demo = r.text
>>> demo
'<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>\r\n</body></html>'
>>> 

我们可以看到输出的text内容是杂乱的,按照上一篇BeautifulSoup库入门,我们可以对他进行美化程一个树形结构,代码为:

from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
print(soup.prettify())

我们将其的结构抽象出来就是这样一个树形结构:

这样来看如果我们要遍历这个树形结构,就有三种方式,如图中的下行遍历、上行遍历和平行遍历(左->右)。

下面分别介绍一下这三种遍历方法:

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

我们用代码来看一下:

>>> soup = BeautifulSoup(demo,"html.parser")
>>> soup.head
<head><title>This is a python demo page</title></head>
>>> soup.head.contents
[<title>This is a python demo page</title>]
>>> soup.body
<body>
<p class="title"><b>The demo python introduces several python courses.</b></p>
<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
 
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>
</body>
>>> soup.body.contents
['\n', <p class="title"><b>The demo python introduces several python courses.</b></p>, '\n', <p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>, '\n']
>>> len(soup.body.contents)
5
>>> soup.body.contents[1]
<p class="title"><b>The demo python introduces several python courses.</b></p>
>>> 

我们可以看出,我们返回的head.contents的类型是一个列表类型,也就是我们可以用列表的方式进行遍历,其中还可以使用len()方法求这个列表的长度,用下标进行遍历,下标数值从0开始表示第一个。

# 遍历儿子节点
for child in soup.body.children:
    print(child)
 
# 遍历子孙节点
for child in soup.body.children:
    print(child)
  • 标签树的上行遍历
属性 说明
.parent 节点的父亲标签
.parents 节点先辈标签的迭代类型,用于循环遍历先辈节点

看代码:

>>> soup = BeautifulSoup(demo,"html.parser")
>>> soup.title.parent
<head><title>This is a python demo page</title></head>
>>> soup.html.parent
<html><head><title>This is a python demo page</title></head>
<body>
<p class="title"><b>The demo python introduces several python courses.</b></p>
<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
 
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>
</body></html>
>>> soup.parent
>>> 

我们可以看到,soup.title的父亲标签就是head,而html标签就是树的根节点了,为最高级标签,所以他的父亲标签还是它本身,soup本身的标签则为空,没有返回任何标签,而事实上如果使用循环已知往上进行遍历最终会遍历到soup,所以我们用下面这个循环来进行上行遍历:

>>> for parent in soup.a.parents:
	if parent is None:
		print(parent)
	else:
		print(parent.name)
 
p
body
html
[document]
>>> 
  • 标签树的平行遍历
属性 说明
.next_sibling 返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling 返回按照HTML文本顺序的上一个平行节点标签
.next_siblings 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

条件:平行遍历发生在同一父亲节点下的各节点间

>>> soup.a.next_sibling
' and '
>>> soup.a.previous_sibling
'Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n'
>>> soup.a.next_sibling.next_sibling
<a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>
>>> soup.a.previous_sibling
'Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n'
>>> soup.a.previous_sibling.previous_sibling
>>> 

我们发现,a标签的下一个标签节点是一个字符串类型,而不是标签类型,这是因为html虽然是由标签类型构成的树形结构,但其实各个标签节点之间还有其他类型的节点,如这个'and',其他的都同上面方法一样。

# 遍历后续节点
for sinling in soup.a.next)siblings:
    print(sibling)
 
# 遍历前续节点
for sibling in soup.a.previous_siblings:
    print(sibling)

4、基于bs4库的HTML格式化和编码

我们之前说到,bs4库的内容遍历方法,那么如何让html的内容更加友好的显示,还记得我们之前提到的demo实例,首先我们用requests库或的demo的html代码,再用beautifulsoup库的prettify()库来打印:

>>> import requests
>>> r = requests.get("http://python123.io/ws/demo.html")
>>> r.status_code
200
>>> demo = r.text
>>> demo
'<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>\r\n</body></html>'
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(demo,"html.parser")
>>> soup.prettify()
'<html>\n <head>\n  <title>\n   This is a python demo page\n  </title>\n </head>\n <body>\n  <p class="title">\n   <b>\n    The demo python introduces several python courses.\n   </b>\n  </p>\n  <p class="course">\n   Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\n   <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">\n    Basic Python\n   </a>\n   and\n   <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">\n    Advanced Python\n   </a>\n   .\n  </p>\n </body>\n</html>'
>>> print(soup.prettify())
<html>
 <head>
  <title>
   This is a python demo page
  </title>
 </head>
 <body>
  <p class="title">
   <b>
    The demo python introduces several python courses.
   </b>
  </p>
  <p class="course">
   Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
   <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
    Basic Python
   </a>
   and
   <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">
    Advanced Python
   </a>
   .
  </p>
 </body>
</html>
>>> 

可以看出,在我们使用prettify()方法输出之前,demo获取的r.text的内容是格式混乱的,当我们使用prettify()方法但并未实际输出时,每一个语句后会多出来一个\n换行符,且会有一定的空格,这说明已经将内容格式美化了,当我们使用输出语句输出美化后的demo内容时,就会输出格式明朗的"标签树"结构内容。

其实prettify()方法还可以对其中给一个标签的内容进行美化,如下面这个:
 

>>> print(soup.a.prettify())
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
 Basic Python
</a>
>>> 

这里需要强调的一点就是prettify()方法可以将html内容自动转换成utf-8的编码格式,这是一种国际通用的支持第三方国家语言显示的编码格式,如下面这个例子:

>>> soup = BeautifulSoup("<p>中文</p>","html.parser")
>>> soup.p.string
'中文'
>>> print(soup.p.prettify())
<p>
 中文
</p>
>>> 

python之路任重道远,加油!!!

猜你喜欢

转载自blog.csdn.net/MARS_098/article/details/104143434