前言
完成网络请求后,拿到完整网页源码只是第一步,从繁杂的 HTML 文本中精准提取目标数据,是爬虫核心环节之一。BeautifulSoup是 Python 生态中经典的 HTML/XML 解析库,语法简洁、上手简单,依托 CSS 选择器、标签层级查找、属性筛选等能力,可快速定位页面元素、提取文本、链接、图片地址等内容,非常适合新手入门网页解析。
结合前文requests请求能力,请求 + 解析构成静态爬虫标准工作流。本章从零讲解 BeautifulSoup 安装、对象结构、核心查询语法、实战筛选规则,搭配大量可运行案例,覆盖标签查找、属性提取、文本获取、节点遍历等常用场景,同时总结解析易错点与优化技巧。
参考文档链接:
- BeautifulSoup 官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/
- lxml 解析器说明:https://lxml.de/
- 在线 HTML 调试工具:https://html-online.com/editor/
一、环境安装与解析器选择
1.1 库安装
BeautifulSoup 不属于 Python 内置库,需通过 pip 安装,同时推荐搭配lxml解析器(速度快、容错性强,工业级首选)。
shell
# 安装 BeautifulSoup4 pip install beautifulsoup4 # 安装 lxml 解析器(必装,推荐) pip install lxml备选解析器:html.parser(Python 内置,无需额外安装,兼容性好但速度偏弱)。
1.2 基础导入与初始化
解析流程固定:请求获取网页源码 → 传入 BeautifulSoup 构建解析对象 → 调用方法查询元素。 基础语法:
python
运行
from bs4 import BeautifulSoup import requests # 1. 发起请求获取网页 url = "https://httpbin.org/html" headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0.0.0 Safari/537.36"} resp = requests.get(url, headers=headers, timeout=5) resp.encoding = "utf-8" html = resp.text # 2. 构建 BeautifulSoup 解析对象 # 参数1:网页源码字符串;参数2:指定解析器 soup = BeautifulSoup(html, "lxml") # 格式化输出完整网页(自动补全标签、排版) print(soup.prettify())关键说明
prettify():格式化 HTML 代码,自动换行、缩进,方便查看页面结构;- 解析器优先级:
lxml> 内置html.parser,正式项目统一使用 lxml; - 若网页存在残缺、不规范标签,lxml 会自动容错修复。
二、BeautifulSoup 四大核心对象
解析后页面会被拆解为四类对象,理解对象类型是灵活解析的基础。
2.1 Tag 标签对象
HTML 中的标签(<div>、<a>、<p>、<img>等)对应 Tag 对象,可获取标签名、属性、内部文本。
python
运行
# 获取第一个 <h1> 标签 h1_tag = soup.h1 # 标签名称 print("标签名:", h1_tag.name) # 标签所有属性(字典格式) print("标签属性:", h1_tag.attrs)2.2 NavigableString 字符串对象
标签内部的文本内容,属于 NavigableString 对象,直接取值即可拿到纯文本。
python
运行
# 获取标签内文本 text = soup.h1.string print("标签文本:", text)2.3 BeautifulSoup 文档对象
整个网页文档本身就是 BeautifulSoup 对象,可视作根节点,所有查找操作都基于该对象发起。
2.4 Comment 注释对象
HTML 注释内容<!-- 注释 -->会被识别为 Comment 对象,解析时注意区分,避免误提取注释文本。
三、基础节点查找(简易用法)
通过soup.标签名可快速获取页面第一个匹配标签,适合结构简单、唯一标签的场景。
3.1 直接通过标签名查找
python
运行
# 获取页面第一个 a 标签 a_tag = soup.a print("a标签完整内容:", a_tag) # 获取a标签文本 print("a标签文本:", a_tag.string) # 获取a标签 href 属性 print("链接地址:", a_tag.get("href")) # 嵌套标签查找:逐层定位 body = soup.body p = body.p print("p标签文本:", p.string)3.2 属性获取两种写法
标签.get("属性名"):推荐写法,属性不存在返回None,不会报错;标签["属性名"]:字典取值写法,属性不存在直接抛异常。
python
运行
tag = soup.a print(tag.get("href")) print(tag["href"])四、重点:find 与 find_all 精准查找
find()和find_all()是项目中使用频率最高的方法,支持按标签、属性、文本多条件筛选,可匹配单个 / 多个元素。
4.1 find ():查找第一个匹配元素
语法:soup.find(name=None, attrs={}, text=None)
- 只返回第一个符合条件的 Tag,无匹配返回
None
4.1.1 按标签名查找
python
运行
# 查找第一个 p 标签 p = soup.find("p") print(p.text)4.1.2 按标签 + 属性查找
支持单属性、多属性筛选,适配带 class、id 的标签。
python
运行
# 查找 class 为 "title" 的 div 标签 div = soup.find("div", class_="title") # 注意:class 是 Python 关键字,语法改为 class_ # 多属性联合筛选 tag = soup.find("a", attrs={"href": "/index.html", "target": "_blank"})4.1.3 按文本内容查找
根据标签内的文字匹配节点:
python
运行
# 查找文本包含 "Hello" 的标签 tag = soup.find(text="Hello World") print(tag)4.2 find_all ():查找所有匹配元素
语法同 find (),返回列表,包含全部符合条件的标签,无匹配返回空列表。
4.2.1 基础用法:批量获取同类型标签
python
运行
# 获取页面所有 a 标签 a_list = soup.find_all("a") print(f"共找到 {len(a_list)} 个链接") # 遍历提取所有链接与文本 for a in a_list: link = a.get("href") text = a.get_text(strip=True) # strip=True 去除首尾空格、换行 print(f"文本:{text} 链接:{link}")4.2.2 多标签同时查找
传入列表,一次性匹配多种标签:
python
运行
# 同时查找所有 p 标签和 h2 标签 tags = soup.find_all(["p", "h2"]) for t in tags: print(t.text.strip())4.2.3 限制返回数量
通过limit参数控制返回标签个数:
python
运行
# 只取前 2 个 a 标签 a_list = soup.find_all("a", limit=2) print(a_list)4.3 文本提取:text /get_text ()
两种方式均可提取标签内所有文本,嵌套标签也会合并内容:
标签.string:仅标签内纯文本,嵌套子标签时返回 None;标签.text/标签.get_text():提取当前标签 + 所有子标签的全部文本;strip=True:自动清除换行、空格、制表符,数据清洗必备。
python
运行
tag = soup.find("div") # 清除空白字符后提取文本 content = tag.get_text(strip=True) print(content)五、CSS 选择器 select(推荐主流用法)
select()方法依托 CSS 选择器语法定位元素,语法直观、和前端通用,复杂页面优先使用 select,是目前行业主流解析方案。
语法:soup.select("CSS选择器")
- 永远返回列表,匹配不到则返回空列表
5.1 常用选择器规则与实战
5.1.1 标签选择器
直接写标签名,匹配所有对应标签:
python
运行
# 选择所有 p 标签 res = soup.select("p") for item in res: print(item.text.strip())5.1.2 class 类选择器
语法:.类名
python
运行
# 选择 class="news" 的所有标签 news_list = soup.select(".news")5.1.3 id 选择器
语法:#id名
python
运行
# 选择 id="main" 的标签 main_tag = soup.select("#main") print(main_tag[0].text.strip())5.1.4 属性选择器
语法:标签[属性=值],精准匹配带指定属性的标签,常用于提取链接、图片:
python
运行
# 选择所有 href 属性为指定值的 a 标签 a_tags = soup.select('a[href="/about"]') # 提取所有图片地址 img_tags = soup.select("img") for img in img_tags: img_url = img.get("src") print("图片链接:", img_url)5.1.5 层级选择器(父子 / 后代)
- 空格分隔:后代选择器(所有下级节点)
>分隔:直接子节点(仅一级子标签)
python
运行
# 查找 div 内部所有 a 标签(后代) res = soup.select("div a") # 查找 div 直接子级 a 标签 res = soup.select("div > a")5.2 select_one ():匹配单个元素
等价于select()[0],专门用于只取第一个匹配项,避免列表取值:
python
运行
# 获取第一个 class="title" 的标签 title = soup.select_one(".title") print(title.text.strip())六、节点遍历(兄弟 / 父子节点)
部分页面结构无唯一 class/id,需通过节点关系遍历查找,适用于规整列表结构。
6.1 子节点与父节点
python
运行
tag = soup.select_one(".list") # 所有直接子节点 children = tag.children for child in children: if child.name: # 过滤空行、文本节点 print(child) # 获取父节点 parent = tag.parent print(parent.name)6.2 兄弟节点(同级标签)
python
运行
# 下一个兄弟节点 next_sib = tag.next_sibling # 上一个兄弟节点 prev_sib = tag.previous_sibling # 所有后面的兄弟节点 all_next = tag.next_siblings七、综合实战 1:列表页数据提取
模拟资讯列表页,完成请求 → 解析 → 批量提取标题、链接、简介全流程,整合前面所有知识点。
python
运行
import requests from bs4 import BeautifulSoup # 基础配置 url = "https://httpbin.org/html" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0.0.0 Safari/537.36" } # 1. 发起请求 resp = requests.get(url, headers=headers, timeout=6) resp.encoding = "utf-8" # 2. 构建解析对象 soup = BeautifulSoup(resp.text, "lxml") # 3. CSS选择器批量提取列表数据 news_items = soup.select("body > p") print("===== 列表数据提取结果 =====") for idx, item in enumerate(news_items, 1): text = item.get_text(strip=True) print(f"第{idx}条:{text}")八、综合实战 2:图片链接批量抓取
实战场景:爬取页面所有图片地址,是爬虫高频需求。
python
运行
import requests from bs4 import BeautifulSoup url = "https://httpbin.org/images" headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0.0.0 Safari/537.36"} resp = requests.get(url, headers=headers, timeout=8) soup = BeautifulSoup(resp.text, "lxml") # 选中所有 img 标签 img_list = soup.select("img") print("页面所有图片链接:") for img in img_list: src = img.get("src") if src: # 拼接完整绝对链接(相对地址补全域名) full_url = url.rstrip("/") + "/" + src.lstrip("/") print(full_url)九、常见问题与避坑指南
9.1 找不到目标标签
- 检查页面是否为JS 动态渲染:BeautifulSoup 只能解析静态 HTML,动态内容无法获取,后续需使用 Selenium/Playwright;
- 核对选择器语法:class、id、标签名大小写严格区分;
- 查看源码:浏览器开发者工具 Elements 面板为准,不要只看预览界面。
9.2 文本出现大量换行、空格
解决方案:提取文本时统一使用get_text(strip=True)清除空白字符。
9.3 class 筛选失效
HTML 中 class 存在多个值时,完整匹配或模糊匹配:
html
预览
<div class="box item"></div>python
运行
# 匹配包含 box 的标签 soup.select(".box")9.4 相对链接无法访问
页面中src="/1.jpg"、href="/index"属于相对路径,必须手动拼接主域名转为绝对链接。