Python使用BeautifulSoup抓取和解析网页数据的入门教程
很多 Python 初学者学完基础语法之后,都会很自然地遇到一个问题:
我能不能把网页里的内容提取下来,变成自己能处理的数据?
比如:
- 抓取文章标题
- 提取商品名称和价格
- 收集招聘信息
- 批量整理博客链接
- 分析网页中的表格和列表
这时候,BeautifulSoup 往往就是最适合入门的工具之一。
它不像大型爬虫框架那样一上来就有很多工程化概念,也不像正则表达式那样容易把人绕晕。它做的事情很纯粹:
帮你解析 HTML,然后从中提取你真正需要的数据。
如果你现在正在学习 Python,又想快速上手网页数据抓取,这篇文章会非常适合你。我们会从 0 开始讲清楚:
- BeautifulSoup 到底是什么
- 它和
requests是什么关系 - 如何抓取网页 HTML
- 如何用
find()、find_all()、select()提取数据 - 如何写出一个完整的小型抓取脚本
- 实际使用时有哪些坑要提前避开
1. BeautifulSoup 是什么
BeautifulSoup 是一个专门用来解析 HTML / XML 文档的 Python 库。
你可以把它理解成一个“网页内容整理器”。
网页源码本来是一大段字符串,里面夹杂了很多标签,比如:
<div class="article"> <h2>Python 入门</h2> <a href="/post/1" rel="external nofollow" rel="external nofollow" >查看详情</a> </div>
如果你直接拿字符串去切片、用正则硬抠,代码会非常脆弱。
而 BeautifulSoup 会先把这段 HTML 解析成一个结构化对象,然后你就可以像查树节点一样去找:
- 某个标签
- 某个 class
- 某个 id
- 某个属性
- 某个标签里的文本
这也是它名字里 Soup 的感觉所在。原本很乱的网页源码,会被它整理成更容易“舀出来”的结构。
2. BeautifulSoup 和 requests 是什么关系
很多新手刚接触网页抓取时,最容易混淆这两个库。
其实职责非常清楚:
requests:负责向网站发请求,把网页内容下载回来BeautifulSoup:负责解析网页内容,并从中提取数据
所以它们常常一起出现:
- 先用
requests.get()拿到 HTML - 再用
BeautifulSoup()把 HTML 解析成对象 - 最后用各种选择器提取需要的数据
一句话记住:
requests 管“拿网页”,BeautifulSoup 管“拆网页”。
3. 先安装依赖
直接安装 BeautifulSoup:
pip install beautifulsoup4
实际抓取网页时,通常还会配合 requests:
pip install requests beautifulsoup4
如果你后面想让解析速度更快,也可以安装 lxml 作为解析器:
pip install lxml
不过对初学者来说,先用 Python 自带的 html.parser 就够了。
4. BeautifulSoup 最基础的使用方式
先不要急着抓真实网站,先用一段本地 HTML 练手,这样最容易理解。
from bs4 import BeautifulSoup
html = """
<html>
<body>
<h1>Python 学习笔记</h1>
<p class="desc">这是一个 BeautifulSoup 示例页面</p>
<a href="/post/1" rel="external nofollow" rel="external nofollow" >第一篇文章</a>
<a href="/post/2" rel="external nofollow" >第二篇文章</a>
</body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.h1.get_text())
print(soup.find("p", class_="desc").get_text())
这段代码里最关键的是:
soup = BeautifulSoup(html, "html.parser")
它表示把字符串形式的 HTML 交给 BeautifulSoup 解析。
后面你就可以通过 soup.h1、find()、select() 这些方式去拿数据。
5. 先掌握最常用的 4 个操作
BeautifulSoup 的 API 不算少,但对于新手来说,真正最常用的就这几个。
5.1find():找第一个匹配标签
title = soup.find("h1")
print(title.get_text())
如果页面里有多个 h1,它只会返回第一个匹配项。
你也可以加属性条件:
desc = soup.find("p", class_="desc")
注意这里是 class_,后面要加下划线,因为 class 是 Python 关键字。
5.2find_all():找所有匹配标签
links = soup.find_all("a")
for link in links:
print(link.get_text(), link.get("href"))
这个方法非常适合提取列表数据,比如:
- 所有文章链接
- 所有商品卡片
- 所有招聘项
5.3select():用 CSS 选择器查找
如果你有一点前端基础,会非常喜欢这个方法。
items = soup.select("a")
desc = soup.select_one("p.desc")
常见写法:
div:选所有div.card:选 class 为card的元素#main:选 id 为main的元素.article-list a:选某个区域下面的所有链接
在很多实际项目中,select() 和 select_one() 会比 find() 更顺手。
5.4get_text()和get()
提取文本:
text = title.get_text(strip=True)
提取属性:
href = link.get("href")
这里要区分清楚:
get_text():拿标签里的文字get("href"):拿标签属性
6. 写一个稍微像样一点的解析示例
下面这段示例会更接近真实项目。
我已经把完整代码整理成单独文件,方便你本地直接运行:
beautifulsoup_web_scraping_demo.py
代码如下:
from __future__ import annotations
from bs4 import BeautifulSoup
import requests
SAMPLE_HTML = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>BeautifulSoup Demo</title>
</head>
<body>
<div class="article-list">
<article class="article-card" data-id="101">
<h2 class="title"><a href="/post/101" rel="external nofollow" >Python 抓取网页入门</a></h2>
<span class="author">小明</span>
<span class="views">1280</span>
</article>
<article class="article-card" data-id="102">
<h2 class="title"><a href="/post/102" rel="external nofollow" >BeautifulSoup 选择器快速上手</a></h2>
<span class="author">小红</span>
<span class="views">980</span>
</article>
<article class="article-card" data-id="103">
<h2 class="title"><a href="/post/103" rel="external nofollow" >requests 和 bs4 配合实战</a></h2>
<span class="author">小李</span>
<span class="views">1560</span>
</article>
</div>
</body>
</html>
"""
def parse_local_html() -> list[dict[str, str]]:
soup = BeautifulSoup(SAMPLE_HTML, "html.parser")
articles: list[dict[str, str]] = []
for card in soup.select(".article-card"):
link = card.select_one(".title a")
author = card.select_one(".author")
views = card.select_one(".views")
if link is None or author is None or views is None:
continue
articles.append(
{
"id": card.get("data-id", ""),
"title": link.get_text(strip=True),
"url": link.get("href", ""),
"author": author.get_text(strip=True),
"views": views.get_text(strip=True),
}
)
return articles
def fetch_page_title(url: str) -> str:
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0 Safari/537.36"
)
}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
if soup.title and soup.title.string:
return soup.title.string.strip()
return "页面没有 title"
def main() -> None:
print("本地 HTML 解析结果:")
for item in parse_local_html():
print(item)
# 真实抓取时,把这里替换成你自己的目标网页。
# 使用前请先确认目标站点允许抓取,并控制请求频率。
# title = fetch_page_title("https://example.com")
# print("页面标题:", title)
if __name__ == "__main__":
main()
这个示例故意分成两部分:
parse_local_html():先教你专注理解 BeautifulSoup 的解析过程fetch_page_title():再告诉你如何把真实网页抓下来后交给 BeautifulSoup
学习这类东西时,建议你也这么练:
先会“解析”,再会“抓取”,最后再把两者组合。
7. 真实抓取网页时的标准流程
很多网站的抓取逻辑,本质上都可以拆成下面这几步:
第一步:发送请求
import requests response = requests.get(url, timeout=10) html = response.text
第二步:构造 BeautifulSoup 对象
from bs4 import BeautifulSoup soup = BeautifulSoup(html, "html.parser")
第三步:定位数据区域
cards = soup.select(".article-card")
第四步:从每个区域中提取字段
for card in cards:
title = card.select_one(".title").get_text(strip=True)
link = card.select_one("a").get("href")
第五步:整理成结构化数据
data.append({
"title": title,
"url": link,
})
所以你会发现,BeautifulSoup 真正的核心工作其实是:
先找到“每条数据的边界”,再从每条记录里拆字段。
这也是写抓取脚本时最重要的思维方式。
8. 新手最常见的一个误区:一上来就抓整页
刚开始学网页抓取时,很多人喜欢一上来就对整页所有标签乱搜。
例如页面里有几十个 a 标签,你直接:
soup.find_all("a")
当然能找到一堆链接,但里面往往混着:
- 导航栏链接
- 广告链接
- 相关文章链接
- 正文链接
- 页脚链接
最后数据会很乱。
更好的做法是:
- 先找到列表区域
- 再在这个区域里找标题、链接、作者、时间
也就是说,尽量从:
soup.select(".article-card")
这种“按块定位”的方式入手,而不是全页面乱抓。
9. BeautifulSoup 常见解析器怎么选
创建对象时你会看到第二个参数:
BeautifulSoup(html, "html.parser")
这里指定的是解析器。
常见的有三个:
html.parser:Python 自带,安装最省事lxml:速度通常更快,项目里很常用html5lib:容错更强,但一般更重
如果你是初学者:
- 学习阶段先用
html.parser - 后面项目里再考虑
lxml
先跑通流程,比一开始纠结性能更重要。
10. 为什么有时抓不到你在浏览器里看到的内容
这是 BeautifulSoup 初学者非常容易遇到的坑。
你在浏览器里明明看到了内容,但 requests.get() 拿回来的 HTML 里却没有。
原因通常是:
页面的数据是通过 JavaScript 动态加载的。
也就是说,浏览器打开页面后,还会继续执行 JS,再向接口请求数据,最后才把内容渲染出来。
而 requests 拿到的只是最初的 HTML。
这时候 BeautifulSoup 没问题,问题在于你抓到的输入源就不完整。
遇到这种情况,常见思路有两个:
- 直接分析网页接口,改抓接口返回的 JSON
- 使用 Playwright、Selenium 这类浏览器自动化工具
所以要记住:
BeautifulSoup 擅长解析 HTML,但它不会替你执行前端 JavaScript。
11. 实战中必须注意的几个问题
这部分比语法更重要。
11.1 不要把网页抓取理解成“复制粘贴源码”
真正的抓取工作,不是看到标签就抄代码,而是要先观察页面结构:
- 每条数据的容器是什么
- 标题在哪个标签
- 链接在哪个属性
- 时间、作者、价格是否都在固定位置
只有先分析结构,BeautifulSoup 才会变得好用。
11.2 记得加请求头
有些网站对默认请求不友好,最简单的处理就是带一个常见浏览器的 User-Agent。
headers = {
"User-Agent": "Mozilla/5.0 ..."
}
response = requests.get(url, headers=headers, timeout=10)
11.3 记得处理异常
不要默认所有请求都会成功。
response.raise_for_status()
至少先把 HTTP 错误暴露出来,否则你很可能在拿一个报错页做解析。
11.4 控制抓取频率
如果你需要抓取多页内容,不要用极高频率连续请求。
这不仅容易失败,也可能给目标网站带来压力。
11.5 尊重站点规则和数据边界
在使用 BeautifulSoup 抓取网页数据前,应该先确认目标站点的使用条款、robots 规则以及数据使用边界。
技术上能抓,不代表业务上就一定适合抓。
12. BeautifulSoup 适合哪些场景
BeautifulSoup 非常适合下面这些任务:
- 网页结构比较稳定
- 页面主要内容就在 HTML 中
- 抓取规模不算特别大
- 想快速写一个轻量脚本
- 想先验证网页数据能不能提取
比如:
- 文章列表抓取
- 简单商品页抓取
- 博客导航页整理
- 表格数据提取
- 页面链接分析
如果你只是想先把网页数据提下来,再做后续分析处理,BeautifulSoup 是一个很好的起点。
13. BeautifulSoup 和 Scrapy 该怎么选
这个问题很多人都会问。
可以这样理解:
- BeautifulSoup 更像“解析工具”
- Scrapy 更像“完整爬虫框架”
如果你的需求是:
- 抓 1 个到几十个页面
- 快速写脚本验证
- 重点在网页解析本身
那么 requests + BeautifulSoup 会更轻、更直接。
如果你的需求是:
- 大量分页抓取
- 自动跟进链接
- 需要统一导出、调度、去重、重试
那通常就要考虑 Scrapy 了。
所以 BeautifulSoup 并不是“低配版 Scrapy”,而是更适合入门和轻量场景的工具。
14. 给初学者的学习建议
如果你想真正学会 BeautifulSoup,不建议只看语法。
更好的学习顺序是:
- 先用本地 HTML 字符串练
find()、find_all()、select() - 再学
requests.get()把网页拿下来 - 再自己挑一个结构简单的页面练手
- 把提取结果整理成字典或列表
- 最后导出成 JSON、CSV 或写入数据库
你会发现,真正的能力不是“会几个 API”,而是:
看到一个网页,能快速判断该从哪里切入提取数据。
15. 总结
BeautifulSoup 是 Python 生态里非常经典、也非常适合新手入门的网页解析库。
它最大的价值不是“语法多高级”,而是把网页提取这件事变得直观了很多。
记住这套组合最核心的分工:
requests:负责抓网页BeautifulSoup:负责拆网页- 你的 Python 代码:负责整理数据和后续处理
如果你正在学习 Python,又希望尽快做出一些“能解决实际问题”的小工具,那么 BeautifulSoup 非常值得你亲手写一遍。
先从本地 HTML 开始,跑通选择器,再去抓真实网页,你的进步会快很多。
以上就是Python使用BeautifulSoup抓取和解析网页数据的入门教程的详细内容,更多关于Python BeautifulSoup抓取和解析网页数据的资料请关注脚本之家其它相关文章!
相关文章
Python+Pandas 获取数据库并加入DataFrame的实例
今天小编就为大家分享一篇Python+Pandas 获取数据库并加入DataFrame的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2018-07-07
Python 利用scrapy爬虫通过短短50行代码下载整站短视频
近日,有朋友向我求助一件小事儿,他在一个短视频app上看到一个好玩儿的段子,想下载下来,可死活找不到下载的方法。经过我的一番研究才找到解决方法,下面小编给大家分享Python 利用scrapy爬虫通过短短50行代码下载整站短视频的方法,感兴趣的朋友一起看看吧2018-10-10


最新评论