python爬虫之BeautifulSoup4库介绍与使用

BeautifulSoup4库

1.介绍

和 lxml库 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。
lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM(Document Object Model)的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。
Beautiful Soup 3 目前已经停止开发,推荐现在的项目使用Beautiful Soup 4。

解析工具 解析速度 使用难度
BeautifulSoup4 最慢 最简单
lxml库 简单
正则 最快 最难

使用以下代码安装BeautifulSoup4库,

pip install bs4

2.使用

2.1.解析html页面

使用bs4库解析html页面,需要先使用BeautifulSoup()方法,实例化一个对象,第一个参数为要解析的html代码,第二个参数为解析方式(如,lxml、html5lib等)。

注意,第二个参数中的解析方式所使用的库,需要提前安装。例如,我们第二个参数设置为lxml,那么我们要保证lxml库已经安装了。

若要显示解析后的html代码,可以直接使用print()打印BeautifulSoup对象,例如,

from bs4 import BeautifulSoup

html = """
职位名称 职位类别 人数 地点 发布时间
22989-金融云区块链高级研发工程师(深圳) 技术类 1 深圳 2017-11-25
22989-金融云高级后台开发 技术类 2 深圳 2017-11-25
SNG16-腾讯音乐运营开发工程师(深圳) 技术类 2 深圳 2017-11-25
SNG16-腾讯音乐业务运维工程师(深圳) 技术类 1 深圳 2017-11-25
TEG03-高级研发工程师(深圳) 技术类 1 深圳 2017-11-24
TEG03-高级图像算法研发工程师(深圳) 技术类 1 深圳 2017-11-24
TEG11-高级AI开发工程师(深圳) 技术类 4 深圳 2017-11-24
15851-后台开发工程师 技术类 1 深圳 2017-11-24
15851-后台开发工程师 技术类 1 深圳 2017-11-24
SNG11-高级业务运维工程师(深圳) 技术类 1 深圳 2017-11-24
"""
soup = BeautifulSoup(html, "lxml") print(soup) # 也可以print(soup.prettify()),这样会显示经过格式化后的html代码,层级更加明显

执行结果如下,

<html><body><table cellpadding="0" cellspacing="0" class="tablelist">
<tbody>
<tr class="h">
<td class="l" width="374">职位名称</td>
<td>职位类别</td>
<td>人数</td>
<td>地点</td>
<td>发布时间</td>
</tr>
<tr class="even">
<td class="l square"><a href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218" target="_blank">22989-金融云区块链高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=29938&keywords=python&tid=87&lid=2218" target="_blank">22989-金融云高级后台开发</a></td>
<td>技术类</td>
<td>2</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
<tr class="even">
<td class="l square"><a href="position_detail.php?id=31236&keywords=python&tid=87&lid=2218" target="_blank">SNG16-腾讯音乐运营开发工程师(深圳)</a></td>
<td>技术类</td>
<td>2</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=31235&keywords=python&tid=87&lid=2218" target="_blank">SNG16-腾讯音乐业务运维工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
<tr class="even">
<td class="l square"><a href="position_detail.php?id=34531&keywords=python&tid=87&lid=2218" target="_blank">TEG03-高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=34532&keywords=python&tid=87&lid=2218" target="_blank">TEG03-高级图像算法研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
<tr class="even">
<td class="l square"><a href="position_detail.php?id=31648&keywords=python&tid=87&lid=2218" target="_blank">TEG11-高级AI开发工程师(深圳)</a></td>
<td>技术类</td>
<td>4</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=32218&keywords=python&tid=87&lid=2218" target="_blank">15851-后台开发工程师</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
<tr class="even">
<td class="l square"><a href="position_detail.php?id=32217&keywords=python&tid=87&lid=2218" target="_blank">15851-后台开发工程师</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
<tr class="odd">
<td class="l square"><a class="test" href="position_detail.php?id=34511&keywords=python&tid=87&lid=2218" target="_blank">SNG11-高级业务运维工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
</tbody>
</table>
</body></html>

我们可以看到,html代码被补全。

2.2.find()与find_all()方法

搜索文档树,一般用得比较多的就是两个方法,一个是find(),一个是find_all()。find()方法是找到第一个满足条件的标签后就立即返回,只返回一个元素。find_all()方法是把所有满足条件的标签都选到,然后生成一个列表返回回去。使用这两个方法,最常用的用法是出入name以及attrs参数找出符合要求的标签。

我们来获取上例中html代码中所有的tr标签,

# 获取所有的tr标签
trs = soup.find_all('tr')
for tr in trs:
    print(tr)
    print("=" * 50)

执行结果如下,

<tr class="h">
<td class="l" width="374">职位名称</td>
<td>职位类别</td>
<td>人数</td>
<td>地点</td>
<td>发布时间</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218" target="_blank">22989-金融云区块链高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
==================================================
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=29938&keywords=python&tid=87&lid=2218" target="_blank">22989-金融云高级后台开发</a></td>
<td>技术类</td>
<td>2</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=31236&keywords=python&tid=87&lid=2218" target="_blank">SNG16-腾讯音乐运营开发工程师(深圳)</a></td>
<td>技术类</td>
<td>2</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
==================================================
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=31235&keywords=python&tid=87&lid=2218" target="_blank">SNG16-腾讯音乐业务运维工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=34531&keywords=python&tid=87&lid=2218" target="_blank">TEG03-高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=34532&keywords=python&tid=87&lid=2218" target="_blank">TEG03-高级图像算法研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=31648&keywords=python&tid=87&lid=2218" target="_blank">TEG11-高级AI开发工程师(深圳)</a></td>
<td>技术类</td>
<td>4</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="odd">
<td class="l square"><a href="position_detail.php?id=32218&keywords=python&tid=87&lid=2218" target="_blank">15851-后台开发工程师</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=32217&keywords=python&tid=87&lid=2218" target="_blank">15851-后台开发工程师</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="odd">
<td class="l square"><a class="test" href="position_detail.php?id=34511&keywords=python&tid=87&lid=2218" target="_blank">SNG11-高级业务运维工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================

我们可以在find_all()方法中添加limit参数获取指定个数的相应标签,例如,我们获取html代码中第二个tr标签,

# 获取第二个tr标签
tr = soup.find_all('tr', limit=2)[-1]
print(tr)

执行结果如下,

<tr class="even">
<td class="l square"><a href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218" target="_blank">22989-金融云区块链高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>

我们可以通过在find()和find_all()方法中添加attrs参数获取指定要求的标签,注意attrs参数为字典形式。例如,获取html代码中class属性为even的tr标签,

# 获取所有class为even的标签
trs = soup.find_all('tr', attrs={'class': 'even'})
for tr in trs:
    print(tr)
    print("=" * 50)

执行结果如下,

<tr class="even">
<td class="l square"><a href="position_detail.php?id=33824&keywords=python&tid=87&lid=2218" target="_blank">22989-金融云区块链高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=31236&keywords=python&tid=87&lid=2218" target="_blank">SNG16-腾讯音乐运营开发工程师(深圳)</a></td>
<td>技术类</td>
<td>2</td>
<td>深圳</td>
<td>2017-11-25</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=34531&keywords=python&tid=87&lid=2218" target="_blank">TEG03-高级研发工程师(深圳)</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=31648&keywords=python&tid=87&lid=2218" target="_blank">TEG11-高级AI开发工程师(深圳)</a></td>
<td>技术类</td>
<td>4</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================
<tr class="even">
<td class="l square"><a href="position_detail.php?id=32217&keywords=python&tid=87&lid=2218" target="_blank">15851-后台开发工程师</a></td>
<td>技术类</td>
<td>1</td>
<td>深圳</td>
<td>2017-11-24</td>
</tr>
==================================================

我们也可以在find()和find_all()方法中直接添加相应属性的值来获取指定标签。例如,我们获取html代码中class和id属性均为test的a标签,

# 获取所有id和class属性为test的a标签
trs = soup.find_all('a', id='test', class_='test')  # 注意class为关键字,因此需要加下划线
for tr in trs:
    print(tr)
    print("=" * 50)

执行结果如下,

<a class="test" href="position_detail.php?id=34511&keywords=python&tid=87&lid=2218" id="test" target="_blank">SNG11-高级业务运维工程师(深圳)</a>
==================================================

我们如果只获取纯文本数据,可以使用string、strings和stripped_strings。

注意,string用与获取单行字符串;strings和stripped_strings用于返回多行字符串,会返回一个生成器。例如,我们使用string获取html中的所有职位信息,

# 获取所有职位的信息(纯文本)
jobs = []  # 建立值为列表,用于存放所有的职位信息
trs = soup.find_all('tr')[1:]  # 因为第一个tr标签为表头,所以从第二个tr开始取值
for tr in trs:
    job = {}
    tds = tr.find_all('td')
    title = tds[0].string
    category = tds[1].string
    num = tds[2].string
    city = tds[3].string
    pub_time = tds[4].string

    # 将相应数据存入job字典
    job['title'] = title
    job['category'] = category
    job['num'] = num
    job['city'] = city
    job['pub_time'] = pub_time
    jobs.append(job)  # 将job字典添加到jobs列表中
print(jobs)

执行结果如下,

[{'title': '22989-金融云区块链高级研发工程师(深圳)', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-25'}, {'title': '22989-金融云高级后台开发', 'category': '技术类', 'num': '2', 'city': '深圳', 'pub_time': '2017-11-25'}, {'title': 'SNG16-腾讯音乐运营开发工程师(深圳)', 'category': '技术类', 'num': '2', 'city': '深圳', 'pub_time': '2017-11-25'}, {'title': 'SNG16-腾讯音乐业务运维工程师(深圳)', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-25'}, {'title': 'TEG03-高级研发工程师(深圳)', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-24'}, {'title': 'TEG03-高级图像算法研发工程师(深圳)', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-24'}, {'title': 'TEG11-高级AI开发工程师(深圳)', 'category': '技术类', 'num': '4', 'city': '深圳', 'pub_time': '2017-11-24'}, {'title': '15851-后台开发工程师', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-24'}, {'title': '15851-后台开发工程师', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-24'}, {'title': 'SNG11-高级业务运维工程师(深圳)', 'category': '技术类', 'num': '1', 'city': '深圳', 'pub_time': '2017-11-24'}]

或接下来,我们使用stripped_strings获取所有职位信息,

jobs = []  # 建立值为列表,用于存放所有的职位信息
trs = soup.find_all('tr')[1:]  # 因为第一个tr标签为表头,所以从第二个tr开始取值
for tr in trs:
    job = {}
    infos = list(tr.stripped_strings)
    job['title'] = infos[0]
    job['category'] = infos[1]
    job['nums'] = infos[2]
    job['city'] = infos[3]
    job['pub_time'] = infos[4]
    jobs.append(job)
print(jobs)

2.3.select()方法

我们也可以使用select()方法获取特定标签。代码如下,

# 获取所有的tr标签
trs = soup.select('tr')  # 返回值为列表
for tr in trs:
    print(tr)
    print(type(tr))
    print("=" * 50)

# 获取第二个tr标签
tr = soup.select('tr')[1]  # 通过列表的下标获取第二个标签
print(tr)

# 获取所有class为even的标签
trs = soup.select('.even')  # 或者使用trs = soup.select('tr[class="even"]'),.属性值为获取指定class属性的标签
for tr in trs:
    print(tr)
    print("=" * 50)

# 将所有id和class为test的a标签找出来
aList = soup.select('#test, .test')  # #属性值为获取指定id属性的值,注意,如果有两个筛选条件需要加逗号分隔
for a in aList:
    print(a)

# 获取所有a标签的属性
aList = soup.select('a')
for a in aList:
    print(a['href'])

# 获取所有职位的信息(纯文本)
trs = soup.select('tr')
for tr in trs:
    infos = list(tr.stripped_strings)
    print(infos)

你可能感兴趣的:(python爬虫之BeautifulSoup4库介绍与使用)