Python爬虫笔记4-BeautifulSoup使用

36次阅读

共计 5041 个字符,预计需要花费 13 分钟才能阅读完成。

BeautifulSoup 介绍
与 lxml 一样,BeautifulSoup 也是一个 HTML/XML 的解析器,主要功能也是如何解析和提取 HTML/XML 数据。
几种解析工具的对比

工具
速度
难度

正则表达式
最快
困难

BeautifulSoup

最简单

lxml

简单

lxml 只会局部遍历,而 Beautiful Soup 是基于 HTML DOM 的,会载入整个文档,解析整个 DOM 树,因此时间和内存开销都会大很多,所以性能要低于 lxml。
安装我的环境是 Python 3.6.5,windows 下 cmd 里执行 pip 安装即可。
pip3 install beautifulsoup4

测试 python 终端里导入 beautifulsoup,无报错信息即安装成功。
>>from bs4 import BeautifulSoup
>>

BeautifulSoup 对象
BeautifulSoup 将复杂的 HTML 文档转换成一个复杂的树形结构, 每个节点都是 Python 对象, 所有对象可以归纳为 4 种:

Tag
NavigableString
BeautifulSoup
Comment

BeautifulSoup 对象表示的是一个文档的内容。大部分时候, 可以把它当作 Tag 对象,是一个特殊的 Tag。Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
Tag
Tag 可以简单理解为 HTML 文档中的一个个的标签,比如:
<head><title>The Dormouse’s story</title></head>
<ur><li class=”item-0″><a href=”link1.html”>first item</a></li></ur>

上面 HTML 文档中的 head、title、ur、li 都是 HTML 标签(节点名称),这些标签加上里面的内容就是 tag。
获取 Tags
# 导入模块
from bs4 import BeautifulSoup

html = “””
<html><head><title>The Dormouse’s story</title></head>
<body>
<p class=”title” name=”dromouse”><b>The Dormouse’s story</b></p>
<p class=”story”>Once upon a time there were three little sisters; and their names 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>
“””
# 初始化 BeautifulSoup 对象,指定 lxml 解析器
soup = BeautifulSoup(html, ‘lxml’)

# prettify()方法格式化 soup 的内容
print(soup.prettify())

# soup.title 选出 title 节点
print(soup.title)
# <title>The Dormouse’s story</title>

print(type(soup.title))
# <class ‘bs4.element.Tag’>

print(soup.head)
# <head><title>The Dormouse’s story</title></head>

print(soup.p)
# <p class=”title” name=”dromouse”><b>The Dormouse’s story</b></p>
说明:使用 soup 加节点名称可以获取节点内容,这些对象的类型是 bs4.element.Tag,但是它查找的是在内容中第一个符合要求的节点。比如上面代码有多个 p 标签,但是它只查找了第一个 p 标签。
对于 Tag 有两个重要的属性,name 和 attrs。当选择一个节点后,name 属性获取节点的名称,attrs 属性获取节点的属性(以字典形式返回)。
print(soup.name)
# [document] #soup 对象本身比较特殊,它的 name 即为 [document]
print(soup.head.name)
# head #对于其他内部标签,输出的值便为标签本身的名称

print(soup.p.attrs)
# {‘class’: [‘title’], ‘name’: ‘dromouse’}
# 在这里,我们把 p 标签的所有属性打印输出了出来,得到的类型是一个字典。

# 下面三种方法都可以获取字典里的值,是等价的,结果都一样
print(soup.p.get(‘class’))
# [‘title’]
print(soup.p[‘class’])
# [‘title’]
print(soup.p.attrs[‘class’])
# [‘title’]

# 还可以针对属性或者内容进行修改
soup.p[‘class’] = “newClass”
print (soup.p)
# <p class=”newClass” name=”dromouse”><b>The Dormouse’s story</b></p>

NavigableString
获取了 Tag,也就是获取了节点内容,但是只想要获取节点内部的内容怎么办?只需使用.string 即可。

# 获取节点内容
print(soup.p.string)
# The Dormouse’s story

print(type(soup.p.string))
# <class ‘bs4.element.NavigableString’>
遍历文档树
在选取节点的时候,也可以先选取一个节点,然后以这个节点为基准选取它的子节点,父节点,子孙节点等等,下面就介绍常用的选取方法。
获取直接子节点.contents .children 属性
.contents
tag 的.contents 属性可以将 tag 的直接子节点以列表的方式输出。下面例子选取 head 节点为基准,.contents 选取 head 的子节点 title,然后以列表返回。
print(soup.head.contents)
# [<title>The Dormouse’s story</title>]
输出方式为列表,可以用列表索引来获取它的某一个元素.
print(soup.head.contents[0])
# <title>The Dormouse’s story</title>

.children
children 属性和 contents 属性不同的是它返回的不是一个列表,而是一个生成器。可用 for 循环输出结果。
print(soup.head.children)
# <list_iterator object at 0x0000017415655588>

for i in soup.head.children:
print(i)
# <title>The Dormouse’s story</title>

获取所有子孙节点:.descendants 属性
上面两个属性都只能获取到基准节点的下一个节点,要想获取节点的所有子孙节点,就可以使用 descendants 属性了。它返回的也是一个生成器。
print(soup.descendants)
# <generator object descendants at 0x0000028FFB17C4C0>

还有其他属性如查找父节点,组父节点的属性就不记录了(平时很少用)。
搜索文档树
BeautifulSoup 提供了一些查询方法 (find_all,find 等),调用对应方法,输入查询参数就可以得到我们想要的内容了,可以理解为搜索引擎的功能。(百度 / 谷歌 = 查询方法,查询内容 = 查询参数,返回的网页 = 想要的内容) 下面介绍最常用的 find_all 方法。
find_all 方法
作用:查找所有符合条件的元素,返回的是列表形式 API:find_all(name, attrs, recursive, text, **kwargs)1. namename 参数可以根据节点名来查找元素。A. 传字符串最简单的过滤器是字符串. 在搜索方法中传入一个字符串参数,BeautifulSoup 会查找与字符串完整匹配的内容, 下面的例子用于查找文档中所有的 <p> 标签。
print(soup.find_all(‘p’))
# 通常以下面方式写比较好
print(soup.find_all(name=’p’))

B. 传正则表达式 如果传入正则表达式作为参数,Beautiful Soup 会通过正则表达式的 match() 来匹配内容. 下面例子中找出所有以 p 开头的标签。
import re
print(soup.find_all(re.compile(‘^p’)))

C. 传列表如果传入列表参数,BeautifulSoup 会将与列表中任一元素匹配的内容返回。下面代码会找到 HTML 代码中的 head 标签和 b 标签。
print(soup.find_all([‘head’,’b’]))
# [<head><title>The Dormouse’s story</title></head>, <b>The Dormouse’s story</b>]

2. attrsfind_all 中 attrs 参数可以根据节点属性查询。查询时传入的参数是字典类型。比如查询 id=link1 的节点
print(soup.find_all(attrs={‘id’:’link1′}))
# [<a class=”sister” href=”http://example.com/elsie” id=”link1″><!– Elsie –></a>]
对于常见的属性,可以不用以 attrs 来传递,直接传入查询参数即可。比如 id,class_(class 为 Python 关键字,使用下划线区分), 如下:
print(soup.find_all(id=’link1′))
print(soup.find_all(class_=’sister’))
运行结果:
[<a class=”sister” href=”http://example.com/elsie” id=”link1″><!– Elsie –></a>]

[<a class=”sister” href=”http://example.com/elsie” id=”link1″><!– Elsie –></a>, <a class=”sister” href=”http://example.com/lacie” id=”link2″>Lacie</a>, <a class=”sister” href=”http://example.com/tillie” id=”link3″>Tillie</a>]

3. texttext 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受 字符串 , 正则表达式 , 列表。下面代码查找节点里内容中有 story 字符串的节点,并返回节点的内容。
print(soup.find_all(text=re.compile(‘story’)))
# [“The Dormouse’s story”, “The Dormouse’s story”]

find 方法
find 方法与 find_all 方法的区别:find_all:查询符合所有条件的元素,返回列表。find: 只查找第一个匹配到的元素,返回单个元素,类型 tag。查询方法与 find_all 大同小异。示例:
print(soup.find(name=’p’)) # 查询第一个 p 标签
print(soup.find(text=re.compile(‘story’))) # 查找第一个节点内容中有 story 字符串的节点内容
运行结果:
<p class=”title” name=”dromouse”><b>The Dormouse’s story</b></p>
The Dormouse’s story

关于 BeautifulSoup 的使用就这样吧,常用个人就觉得用好 find_all 即可(=.=~)
参考链接
崔庆才 [Python3 网络爬虫开发实战]:4.2- 使用 Beautiful Soup

正文完
 0