☰
Python进阶教程:22_BeautifulSoup 网页解析 零基础超详细教程
2026/10/6 13:05:30 网站建设 项目流程

BeautifulSoup 是 Python 爬虫领域最经典的HTML/XML 解析库,核心作用是从网页源码中精准提取你想要的数据。 通俗理解:如果把网页比作一本杂乱的书,requests负责把书下载下来,BeautifulSoup 就是帮你快速翻书、定位指定内容的智能工具 —— 不用逐行找、不用写复杂的正则表达式,通过标签名、属性、CSS 选择器就能快速抠出数据,是新手入门爬虫的必学工具。

本文从环境搭建、基础语法到完整实战,全程配可运行代码 + 逐行解释 + 避坑指南,零基础也能一步步上手。

⚠️ 合规提示:本文仅用于技术学习,请遵守目标网站的robots协议,不要恶意爬取、批量请求他人网站。


一、前置说明

1. BeautifulSoup 的定位

它只能解析已经拿到的网页源码,本身不能下载网页。爬虫的标准流程是:

  1. 用requests等库发送请求,下载网页的 HTML 源码
  2. 把源码交给 BeautifulSoup 解析,提取目标数据

补充:BeautifulSoup 只能处理静态 HTML(浏览器右键 “查看网页源码” 能看到的内容);如果是 JavaScript 动态渲染的内容(比如需要滚动、点击才加载的数据),直接拿源码是看不到的,需要配合 Selenium 或者抓接口。

2. 安装

BeautifulSoup 是第三方库,需要手动安装。注意库名是beautifulsoup4(末尾的 4 是版本号):

pip install beautifulsoup4

3. 关于解析器

BeautifulSoup 本身只提供解析逻辑,需要搭配解析器使用,新手记住两种即可:

解析器说明推荐度
html.parserPython 内置,无需额外安装,足够应对绝大多数场景⭐⭐⭐⭐⭐(新手首选)
lxml第三方解析器,解析速度更快,需要单独安装pip install lxml⭐⭐⭐⭐

本文所有例子都用内置的html.parser,不用额外装东西。


二、快速入门:第一个解析示例

我们先不用联网,用一段手写的 HTML 字符串演示,直观感受 BeautifulSoup 的用法。

完整入门代码

# 1. 导入库:从 bs4 包里导入 BeautifulSoup 类 from bs4 import BeautifulSoup # 2. 准备一段HTML源码(模拟我们下载到的网页内容) html_doc = """ <html> <head> <title>测试网页标题</title> </head> <body> <h1 class="main-title">欢迎来到测试网站</h1> <p class="intro">这是一个用于测试BeautifulSoup的示例网页。</p> <ul class="news-list"> <li><a href="news/1.html" class="news-link">第一条新闻</a></li> <li><a href="news/2.html" class="news-link">第二条新闻</a></li> <li><a href="news/3.html" class="news-link">第三条新闻</a></li> </ul> <div id="footer"> <p>版权所有 © 2024</p> </div> </body> </html> """ # 3. 创建BeautifulSoup解析对象 # 第一个参数:HTML源码字符串 # 第二个参数:解析器,这里用内置的html.parser soup = BeautifulSoup(html_doc, "html.parser") # 4. 提取数据:获取网页标题 title = soup.title.string print("网页标题:", title) # 5. 提取所有新闻链接的文本和地址 links = soup.find_all("a", class_="news-link") print("\n所有新闻:") for link in links: # .text 获取标签内的文字;.get("href") 获取href属性的值 print(f"标题:{link.text},链接:{link.get('href')}")

运行结果:

网页标题: 测试网页标题 所有新闻: 标题:第一条新闻,链接:news/1.html 标题:第二条新闻,链接:news/2.html 标题:第三条新闻,链接:news/3.html

逐行解释核心步骤

  1. BeautifulSoup(html_doc, "html.parser"):把字符串格式的 HTML,变成结构化的「解析对象」,之后所有提取操作都通过这个对象完成
  2. soup.title:直接找到页面里第一个<title>标签
  3. .string:获取标签里的文本内容
  4. soup.find_all("a", class_="news-link"):找到所有class="news-link"的<a>标签,返回列表
  5. .get("href"):安全获取标签的href属性值

三、核心解析方法(重点必学)

BeautifulSoup 提供了多种提取数据的方法,新手优先掌握最常用的 3 类:标签直接选择、find()/find_all()、CSS 选择器select()。

1. 直接通过标签名选择

最简单的写法:soup.标签名,直接找到页面中第一个匹配的标签。

示例
from bs4 import BeautifulSoup soup = BeautifulSoup(html_doc, "html.parser") # 获取第一个h1标签 h1 = soup.h1 print(h1) # <h1 class="main-title">欢迎来到测试网站</h1> # 获取第一个a标签 first_a = soup.a print(first_a) # <a href="news/1.html" class="news-link">第一条新闻</a>

⚠️ 注意:这种方式只能拿到第一个匹配的标签,适合页面里只有一个该标签的场景(比如 title);要找多个必须用后面的find_all()。


2. find () 和 find_all ()(最核心最常用)

这是 BeautifulSoup 最核心的两个方法,90% 的提取场景都用它们。

方法作用返回值
find()找第一个符合条件的标签单个标签对象,找不到返回 None
find_all()找所有符合条件的标签标签对象组成的列表,找不到返回空列表
通用语法
soup.find(name="标签名", attrs={"属性名": "属性值"}, text="文本内容") soup.find_all(name="标签名", attrs={"属性名": "属性值"}, text="文本内容")

用法 1:只按标签名查找
# 找到所有的li标签 all_li = soup.find_all("li") print(f"找到{len(all_li)}个li标签") # 找到第一个p标签 first_p = soup.find("p") print("第一个p标签内容:", first_p.text)

用法 2:按属性查找(最常用)

通过标签的class、id、href等属性精准定位,有两种写法:

写法 A:通过attrs字典传属性(通用写法)
# 找到id为footer的div标签 footer = soup.find("div", attrs={"id": "footer"}) print(footer.text.strip()) # 版权所有 © 2024 # 找到所有class为news-link的a标签 links = soup.find_all("a", attrs={"class": "news-link"})
写法 B:关键字参数简写(更常用)
# 按id查找 footer = soup.find("div", id="footer") # 按class查找:注意class后面要加下划线_! # 因为class是Python的关键字,直接写会语法报错 links = soup.find_all("a", class_="news-link")

⚠️ 新手头号坑:class是 Python 关键字,作为参数必须写成class_(加下划线),否则直接语法报错!


用法 3:按文本内容查找

通过text参数匹配标签里的文字:

# 找到文本为"第二条新闻"的a标签 target = soup.find("a", text="第二条新闻") print(target.get("href")) # news/2.html

注意:text是完全匹配,必须和标签里的文字一模一样才行;模糊匹配需要配合正则表达式。


3. 获取标签的文本和属性

找到标签对象后,我们最常用两个操作:拿文字、拿属性值。

① 获取文本内容
写法作用推荐度
.text获取标签内所有文本(包括子标签里的文字),自动拼接⭐⭐⭐⭐⭐(最常用)
.get_text()和.text 效果一致,还可以加参数控制分隔符⭐⭐⭐⭐
.string仅当标签内只有纯文本、没有子标签时才能拿到,否则返回 None⭐⭐

示例:

div = soup.find("div", id="footer") print(div.text) # 版权所有 © 2024 print(div.get_text(strip=True)) # 自动去掉首尾空白
② 获取属性值

表格

写法作用推荐度
.get("属性名")属性存在返回值,不存在返回 None,不会报错⭐⭐⭐⭐⭐(安全首选)
["属性名"]属性不存在直接报错⭐⭐

示例:

a_tag = soup.find("a") print(a_tag.get("href")) # news/1.html print(a_tag.get("class")) # ['news-link'] print(a_tag.get("xxx")) # None(属性不存在,不报错)

4. CSS 选择器:select () 方法

如果你懂前端 CSS 选择器,用select()会非常顺手,语法和 CSS 完全一致,返回匹配的所有元素列表。

常用选择器对应写法
选择器类型示例作用
标签选择器soup.select("a")找到所有 a 标签
class 选择器soup.select(".news-link")找到所有 class 为 news-link 的元素
id 选择器soup.select("#footer")找到 id 为 footer 的元素
后代选择器soup.select("ul li a")找到 ul 里面的 li 里面的 a
子选择器soup.select("ul > li")找到 ul 的直接子元素 li
示例
# 找到所有新闻链接 links = soup.select("ul.news-list a.news-link") for link in links: print(link.text, link.get("href")) # 找到id为footer的div里的p标签 footer_p = soup.select("#footer p") print(footer_p[0].text)

补充:select()永远返回列表,哪怕只有一个结果也要用[0]取出来;如果只要第一个,可以用select_one(),返回单个元素。


四、进阶:标签层级导航

有时候我们先找到一个父标签,再在它内部找子标签,这就是「相对查找」,可以避免页面其他同名标签的干扰。

在标签内部继续查找

标签对象本身也支持find()、find_all()、select()等所有方法,只在当前标签的内部查找:

# 先找到整个ul父标签 ul_tag = soup.find("ul", class_="news-list") # 只在ul内部找a标签,不会找到页面其他地方的a links = ul_tag.find_all("a")

其他层级属性(了解即可)

  • .parent:获取当前标签的父标签
  • .children:获取所有直接子标签(迭代器)
  • .next_sibling/.previous_sibling:下一个 / 上一个同级兄弟标签

五、完整实战:requests + BeautifulSoup 爬取练习网站

我们用专门的爬虫练习网站https://quotes.toscrape.com/做完整实战,这个网站没有反爬、结构清晰,专门供新手练习。

需求

爬取第一页的所有名言、作者、标签。

完整代码 + 逐行解释

# 1. 导入需要的库 import requests from bs4 import BeautifulSoup # 2. 目标网址 url = "https://quotes.toscrape.com/" # 3. 发送GET请求,获取网页响应 # 加User-Agent模拟浏览器,避免被拦截 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } response = requests.get(url, headers=headers) # 4. 设置编码,防止中文乱码 response.encoding = "utf-8" # 5. 把响应的HTML文本交给BeautifulSoup解析 soup = BeautifulSoup(response.text, "html.parser") # 6. 定位所有名言条目:每个名言都在class为quote的div里 quote_items = soup.find_all("div", class_="quote") print(f"共找到{len(quote_items)}条名言:\n") # 7. 遍历每条,提取详细信息 for index, item in enumerate(quote_items, 1): # 提取名言内容:在class为text的span里 text = item.find("span", class_="text").text.strip("“”") # 提取作者:在class为author的small标签里 author = item.find("small", class_="author").text # 提取标签:所有class为tag的a标签 tags = [tag.text for tag in item.find_all("a", class_="tag")] # 打印结果 print(f"【第{index}条】") print(f"名言:{text}") print(f"作者:{author}") print(f"标签:{', '.join(tags)}") print("-"*50)

运行效果

共找到10条名言: 【第1条】 名言:The world as we have created it is a process of our thinking. 作者:Albert Einstein 标签:change, deep-thoughts, thinking, world -------------------------------------------------- ...

关键步骤说明

  1. 加请求头:User-Agent模拟浏览器,防止网站识别为爬虫直接拒绝
  2. 编码设置:response.encoding = "utf-8"避免中文乱码;如果不确定编码,可以用response.apparent_encoding自动识别
  3. 先找父容器,再找子元素:先定位每个名言的大盒子div.quote,再在里面分别提取文字、作者、标签,结构清晰不容易错

六、新手高频易错点 & 避坑指南

1.class忘加下划线

❌ 错误:soup.find("a", class="news-link")✅ 正确:soup.find("a", class_="news-link")原因:class是 Python 关键字,不能直接当参数名。

2.find_all()结果直接.text报错

find_all()返回的是列表,不是单个标签对象,不能直接.text,必须遍历或者用下标取单个元素。 ❌ 错误:soup.find_all("a").text✅ 正确:

links = soup.find_all("a") for link in links: print(link.text)

3. 找不到元素,先看源码对不对

如果定位语法没错但就是找不到元素,先打印soup.prettify()看看拿到的源码是不是和浏览器里的一样:

  • 如果源码里根本没有这个内容 → 是 JS 动态渲染的,BeautifulSoup 搞不定,需要用 Selenium 或者抓接口
  • 如果源码里有 → 检查标签名、属性名有没有写错,注意大小写、拼写

4. 属性值有多个 class 时的匹配问题

如果一个标签有多个 class,比如<div class="item active">,用class_="item"是可以匹配到的,BeautifulSoup 会匹配单个 class。

5. 网页乱码

拿到的内容中文全是乱码,基本都是编码没设置对:

# 手动指定编码 response.encoding = "utf-8" # 或者自动识别编码 response.encoding = response.apparent_encoding

七、调试小技巧

print(soup.prettify())可以把解析后的 HTML 格式化输出,结构清晰,调试的时候用来检查拿到的源码对不对、元素结构是什么样的,非常好用。


八、核心总结

  1. 定位:BeautifulSoup 是解析工具,负责从 HTML 源码里提取数据,配合 requests 下载网页使用
  2. 核心方法:
    • 找单个:find()
    • 找所有:find_all()
    • CSS 选择器:select()/select_one()
  3. 取值:
    • 文本:.text/.get_text()
    • 属性:.get("属性名")
  4. 避坑:class_加下划线、find_all 返回列表要遍历、动态页面用不了

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询