上一篇我们用 requests 把网页源码"拿下来"了。
但拿到手的是什么?一大坨 HTML 标签,尖括号套尖括号,密密麻麻的。你想要的标题、链接、价格、正文,全混在里面。总不能手动一条条复制粘贴吧?
那也太蠢了。
今天的主角 BeautifulSoup,就是专门干这个的------从一堆 HTML 里,精准把你想要的数据"抠"出来。
BeautifulSoup 是什么?
一句话说清楚:它是一个 HTML/XML 解析库,能帮你从网页源码里精准提取你想要的内容。
打个比方:requests 是帮你把整棵树(网页)搬回家的人,而 BeautifulSoup 是帮你从树上摘果子的人。一个负责"拿回来",一个负责"挑出来"。
它不下载网页,它只负责解析。
安装
打开终端,输入:
bash
pip install beautifulsoup4
注意是 beautifulsoup4 ,不是 beautifulsoup。后者是老版本,没人用了。
另外建议再装一个解析器:
bash
pip install lxml
lxml 解析速度快,功能强,BeautifulSoup 可以直接用它当底层解析器。
基本用法
第一步:导入和初始化
python
from bs4 import BeautifulSoup
# 假设 html 是你用 requests 拿到的网页源码
soup = BeautifulSoup(html, 'lxml')
就两行。第一行把库引进来,第二行把 HTML 字符串丢进去解析,得到一个 soup 对象。
后面所有提取操作都基于这个对象。
find ------ 找第一个元素
如果你只想找页面上第一个 <h1> 标签:
python
title = soup.find('h1')
print(title)
# <h1>这是标题</h1>
find 只会返回第一个匹配的元素。页面上有十个 h1 它也只给你第一个。
find_all ------ 找所有元素
如果你想找页面上所有 的 <a> 标签(也就是所有链接):
python
links = soup.find_all('a')
print(links)
# [<a href="xxx">链接1</a>, <a href="yyy">链接2</a>, ...]
find_all 返回的是一个列表,里面装着所有匹配的元素。
通过属性找元素
光靠标签名不够精准。页面上可能有几十个 <div>,但你要的只是 class 为 book-item 的那几个。
按 class 找:
python
# 注意是 class_,不是 class
item = soup.find('div', class_='book-item')
为什么是 class_ 不是 class?因为 class 在 Python 里是定义类的关键字,不能当参数名用。加个下划线就绕开了。
按 id 找:
python
content = soup.find(id='main-content')
id 不用加下划线,因为 id 不是 Python 的关键字。
同时指定多个属性:
python
item = soup.find('div', class_='book-item', id='book-1')
条件越多,定位越精准。
提取文本内容
找到元素之后,怎么拿到里面的文字?
python
title = soup.find('h1')
# 方法一:.text
print(title.text)
# 这是标题
# 方法二:.get_text()
print(title.get_text())
# 这是标题
两种都能用,效果差不多。.get_text() 支持更多参数,可以控制分隔符、要不要去空白之类的。日常用 .text 就行。
提取属性值
比如你找到了一个 <a> 标签,想拿到它的 href 链接地址:
python
link = soup.find('a')
# 方法一:用方括号
print(link['href'])
# https://example.com
# 方法二:用 .get()
print(link.get('href'))
# https://example.com
推荐用 .get() 。为什么?因为如果属性不存在,方括号的方式会直接报错崩溃,而 .get() 会返回 None,程序还能继续跑。
写爬虫的原则是:宁可不拿数据,也不能崩了。
CSS 选择器:select()
除了 find 和 find_all,BeautifulSoup 还支持 CSS 选择器,用 select() 方法。
如果你写过 CSS,简直无缝衔接。
按 class 选(前面加个点)
python
# 选出所有 class="book-item" 的元素
items = soup.select('.book-item')
按 id 选(前面加个井号)
python
# 选出 id="main" 的元素
main = soup.select('#main')
组合使用
python
# 选出 class="book-list" 下面的所有 <li>
books = soup.select('.book-list li')
# 选出 class="title" 的 <h3>
titles = soup.select('h3.title')
select() 返回的永远是列表,哪怕只有一个结果。
如果你只要第一个,可以用 select_one():
python
first_title = soup.select_one('.book-title')
简单的提取用 find/find_all,复杂的层级关系用 select,怎么顺手怎么来。
实战案例:提取书籍列表
光说不练假把式,我们来搞一个完整的例子。
假设我们有这样一个书籍列表页面:
html
<html>
<head>
<title>梅雅达书店</title>
</head>
<body>
<h1>畅销书籍列表</h1>
<div class="book-list">
<div class="book-item">
<h3 class="book-title">Python编程从入门到实践</h3>
<p class="book-author">作者:埃里克·马瑟斯</p>
<p class="book-price">价格:¥89.00</p>
<p class="book-desc">一本适合初学者的Python经典入门书。</p>
<a href="/books/1" class="book-link">查看详情</a>
</div>
<div class="book-item">
<h3 class="book-title">流畅的Python</h3>
<p class="book-author">作者:卢西亚诺·拉马略</p>
<p class="book-price">价格:¥139.00</p>
<p class="book-desc">Python进阶必读,深入理解Python语言特性。</p>
<a href="/books/2" class="book-link">查看详情</a>
</div>
<div class="book-item">
<h3 class="book-title">算法图解</h3>
<p class="book-author">作者:阿德南·巴哈伊</p>
<p class="book-price">价格:¥69.00</p>
<p class="book-desc">像小说一样有趣的算法入门书。</p>
<a href="/books/3" class="book-link">查看详情</a>
</div>
</div>
</body>
</html>
现在我们要把所有书名和链接提取出来。
python
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'lxml')
# 找到所有书籍项
book_items = soup.find_all('div', class_='book-item')
# 遍历每一本书,提取书名和链接
for item in book_items:
title = item.find('h3', class_='book-title').text
link = item.find('a', class_='book-link').get('href')
print(f"书名:{title}")
print(f"链接:{link}")
print("---")
运行结果:
书名:Python编程从入门到实践
链接:/books/1
---
书名:流畅的Python
链接:/books/2
---
书名:算法图解
链接:/books/3
---
搞定。三本书的信息全部提取出来了。
想加作者和价格?照着同样的思路,多加两行 find 就行。
新手最容易踩的三个坑
坑1:class 写成 class,报错了
python
# ❌ 错的
soup.find('div', class='item')
# ✅ 对的
soup.find('div', class_='item')
这个 90% 的新手都踩过。看到 SyntaxError: invalid syntax 先检查是不是把 class_ 写成 class 了。
坑2:find 找不到,直接 .text 崩溃
python
title = soup.find('h1')
print(title.text) # 如果页面上没有 h1,title 是 None,直接崩
安全写法:先判断再用。
python
title = soup.find('h1')
if title:
print(title.text)
else:
print("没找到标题")
写爬虫要有"找不到是常态"的心态,不要假设每一个元素一定存在。
坑3:find_all 返回列表,你直接 .text
python
links = soup.find_all('a')
print(links.text) # ❌ 错的!列表没有 .text 属性
正确做法:遍历列表。
python
links = soup.find_all('a')
for link in links:
print(link.text, link.get('href'))
find_all 拿到的是一筐苹果,你得一个个拿出来才能削皮。
今天学了什么
最后帮你梳理一下今天的核心方法:
| 方法 | 作用 | 返回值 |
|---|---|---|
soup.find('标签') |
找第一个匹配的元素 | 单个元素 或 None |
soup.find_all('标签') |
找所有匹配的元素 | 列表 |
element.text |
提取元素文本 | 字符串 |
element.get('属性名') |
提取属性值 | 字符串 或 None |
soup.select('选择器') |
用CSS选择器找元素 | 列表 |
soup.select_one('选择器') |
用CSS选择器找第一个 | 单个元素 或 None |
记住这 6 个方法,80% 的网页提取场景你都能搞定。
下一篇我们讲表格数据专项抓取------网页上的表格怎么一键提取,懒人必备。
本文仅讲解核心思路与关键代码片段,适合零基础学习原理。
完整可运行工程源码、配套测试数据、详细逐行注释、常见报错排错文档已打包成资源。
【资源说明】
- 所有资源仅限个人学习使用,禁止商用、二次倒卖、公开分发
- 包含完整源码 + 测试数据 + 使用文档
- 不含一对一远程调试、环境配置答疑服务
- 适合直接复用、写作业、练项目、做个人作品集
【合规声明】
本项目仅用于公开静态网页、公开学习数据采集练习,禁止用于商业爬取、高频爬取、隐私数据爬取,使用者自行承担使用责任。
©️ 梅雅达编程笔记原创 · 首发 CSDN · 转载请注明出处