杰瑞科技汇

BeautifulSoup如何高效解析HTML?

什么是 Beautiful Soup?

Beautiful Soup 是一个 Python 库,它的主要功能是解析遍历 HTML/XML 文档,并提供一种简单、符合人类直觉的方式来导航、搜索和修改解析树。

BeautifulSoup如何高效解析HTML?-图1
(图片来源网络,侵删)

它的作用就是:

  1. 接收一个 HTML/XML 文档(字符串或文件句柄)。
  2. 解析它,将其转换成一个复杂的树形结构(我们称之为“解析树”或“Soup 对象”)。
  3. 提供一套简单的方法,让你可以方便地在这个树中查找、定位和提取你想要的数据。

为什么选择 Beautiful Soup?

直接用 Python 的字符串处理方法(如 split(), find(), replace())来解析 HTML 是非常痛苦且低效的,因为 HTML 结构复杂,标签嵌套、属性多变。

Beautiful Soup 的优势在于:

  • 容错性强:它能很好地处理不规范的、甚至有错误的 HTML 代码,这是它最强大的特点之一。
  • API 简单易用:提供了非常直观的 API,学习成本低,上手快。
  • 功能强大:支持多种解析器,并且提供了强大的搜索方法(如 find(), find_all())。
  • 文档完善:官方文档非常详细,有大量的例子和教程。

安装与基本使用

1 安装

你需要安装 Beautiful Soup 库,强烈建议你安装一个解析器,lxml,它的速度和容错性都很好。

BeautifulSoup如何高效解析HTML?-图2
(图片来源网络,侵删)
# 安装 beautifulsoup4 库本身
pip install beautifulsoup4
# 安装一个高效的解析器 (推荐)
pip install lxml
# 也可以使用 Python 内置的 html.parser
# pip install html5lib  # 另一个容错性极强的解析器

2 基本使用流程

Beautiful Soup 的使用通常遵循以下三步:

  1. 导入库from bs4 import BeautifulSoup
  2. 创建 Soup 对象:将网页源代码(字符串)或文件传递给 BeautifulSoup 构造函数。
  3. 查找和提取数据:使用 Soup 对象的方法(如 .find(), .find_all(), .select() 等)来定位元素。

核心概念与方法

假设我们有下面这段 HTML 代码作为示例:

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three 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>
"""

1 创建 Soup 对象

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'lxml') # 使用 lxml 解析器

2 导航和查找

Beautiful Soup 提供了两种主要的查找方式:

A. 树形导航 (.find().find_all())

BeautifulSoup如何高效解析HTML?-图3
(图片来源网络,侵删)

这是最核心、最常用的方法。

  • .find(name, attrs, recursive, ...)查找第一个匹配的元素。
  • .find_all(name, attrs, recursive, ...)查找所有匹配的元素,返回一个列表。

示例:

# 1. 查找标签名
# 查找第一个 <a> 标签
first_a_tag = soup.find('a')
print(f"第一个 a 标签: {first_a_tag}")
# 输出: 第一个 a 标签: <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
# 查找所有的 <a> 标签
all_a_tags = soup.find_all('a')
print(f"\n所有的 a 标签: {all_a_tags}")
# 输出: 所有的 a 标签: [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, ...]
# 2. 使用属性查找
# 查找 id 为 "link2" 的标签
link2 = soup.find(id='link2')
print(f"\nID 为 link2 的标签: {link2}")
# 输出: ID 为 link2 的标签: <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
# 查找 class 为 "sister" 的所有标签 (注意:class 是 Python 的保留字,所以用 class_)
sister_tags = soup.find_all(class_='sister')
print(f"\nClass 为 sister 的所有标签: {sister_tags}")
# 3. 组合查找
# 查找所有 <a> 标签,class 是 "sister"
a_sisters = soup.find_all('a', class_='sister')
print(f"\n所有 a 标签且 class 为 sister: {a_sisters}")
# 查找所有 <p> 标签,class 是 "story"
p_stories = soup.find_all('p', class_='story')
print(f"\n所有 p 标签且 class 为 story: {p_stories}")

B. CSS 选择器 (.select().select_one())

如果你熟悉 CSS 选择器,这种方式会更加灵活和强大。

  • .select(css_selector)查找所有匹配 CSS 选择器的元素,返回一个列表。
  • .select_one(css_selector)查找第一个匹配 CSS 选择器的元素。

示例:

# 1. 通过标签名选择
p_tags = soup.select('p')
print(f"所有 p 标签: {p_tags}")
# 2. 通过类名选择 (加点 .)class = soup.select('.title')
print(f"\nClass 为 title 的标签: {title_class}")
# 3. 通过 ID 选择 (加井号 #)
link1_id = soup.select('#link1')
print(f"\nID 为 link1 的标签: {link1_id}")
# 4. 组合选择 (后代选择器)
# 查找 body 内部的所有 a 标签
body_a_tags = soup.select('body a')
print(f"\nbody 内部的所有 a 标签: {body_a_tags}")
# 5. 属性选择 (用方括号 [])
# 查找所有 href 属性包含 "example.com" 的 a 标签
href_example = soup.select('a[href*="example.com"]')
print(f"\nhref 包含 example.com 的 a 标签: {href_example}")

3 提取信息

找到元素后,下一步就是提取我们关心的信息:文本、链接、图片地址等。

# 假设我们已经找到了一个标签
a_tag = soup.find('a', id='link1')
# 1. 获取文本内容
# .string: 如果标签内只有一个字符串,返回该字符串
# .text: 获取标签内所有内容(包括子孙标签的文本),并拼接成一个字符串
# .get_text(): 和 .text 类似,但更灵活,可以控制分隔符等
name = a_tag.string
print(f"标签内的文本: {name}") # 输出: Elsie
all_text_in_p = soup.find('p', class_='story').text
print(f"story p 标签内的所有文本: {all_text_in_p}")
# 2. 获取属性值
# 直接像字典一样访问,或使用 .get() 方法
href = a_tag['href']
# 或者
href_get = a_tag.get('href')
print(f"链接地址: {href}") # 输出: http://example.com/elsie
# 获取 class 属性 (返回的是一个列表)
class_list = a_tag['class']
print(f"Class 属性列表: {class_list}") # 输出: ['sister']

完整实例:抓取网页标题和所有链接

下面是一个完整的例子,展示如何抓取一个网页的标题和所有链接。

import requests
from bs4 import BeautifulSoup
# 1. 获取网页内容
url = 'http://quotes.toscrape.com/' # 一个用来练习的网站
try:
    response = requests.get(url)
    response.raise_for_status()  # 如果请求失败 (
分享:
扫描分享到社交APP
上一篇
下一篇