单元 2 · 数据解析 — 预计 45 分钟
BeautifulSoup 解析
📍 本课路径
- 用 BeautifulSoup 解析 HTML
- 用 find / find_all / select 定位元素
- 遍历父子与兄弟节点
- 正确提取文本与属性
🎯 学习节奏:① 看目标 → ② 先思考再动手 → ③ 在运行器写代码 → ④ 失败时按提示重试 → ⑤ 通过后看思路
拿到网页字符串只是开始,真正的功夫在解析——把杂乱的 HTML 变成你能按规则提取数据的结构。BeautifulSoup(BS4)是 Python 里最友好的解析库。
一、解析器怎么选
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser") # Python 内置,零依赖
soup = BeautifulSoup(html, "lxml") # 更快,需装 lxml(推荐)
教程统一用 "lxml"(快),它也能解析不规范的 HTML。下面所有示例都基于它。
二、三种定位方式
- 按标签名:
soup.find('title')找第一个,soup.find_all('a')找全部。 - 按属性:
soup.find('div', class_='book')(class要写成class_,因为 class 是 Python 关键字)。 - CSS 选择器(最常用):
soup.select('div.book > span.title')返回列表,select_one返回单个。
下面需要你补全提取逻辑——给定一段图书列表 HTML,用 CSS 选择器取出每本书的书名和价格:
from bs4 import BeautifulSoup
html = """<ul class="books">
<li class="book"><span class="title">Python 入门</span><span class="price">59</span></li>
<li class="book"><span class="title">爬虫实战</span><span class="price">69</span></li>
</ul>"""
# TODO 1: 用 BeautifulSoup 解析 html,指定 lxml 解析器
soup = BeautifulSoup(html, "lxml")
# TODO 2: 用 soup.select("li.book") 找到所有书,遍历每一本
for li in soup.select("li.book"):
# TODO 3: 用 select_one(".title") 取书名文本,select_one(".price") 取价格文本
title = li.select_one(".title").get_text(strip=True)
price = li.select_one(".price").get_text(strip=True)
print(title, price)三、遍历节点树
HTML 是树,BS4 让你上下左右走:
- 父:
tag.parent - 子:
tag.contents(列表)/tag.children(迭代器) - 兄弟:
tag.next_sibling/tag.previous_sibling - 后代文本:
tag.get_text()把所有嵌套文字拼起来
提取文字用
.get_text(),不要直接str(tag)——后者会把标签也带进去。
四、属性与文本的正确姿势
- 取属性:
tag['href']或tag.get('href')(推荐get,没有时返回 None 不报错)。 - 取文本:
tag.get_text(strip=True)的strip=True能顺手去掉首尾空白,实战必加。 - 批量属性:
[a.get('href') for a in soup.select('a')]。
再来一个练习,这次链接文字前后有多余空格和换行,你需要正确清洗:
from bs4 import BeautifulSoup
html = """<div class="list">
<a href="/p/1"> Python 入门 </a>
<a href="/p/2">
爬虫实战
</a>
</div>"""
soup = BeautifulSoup(html, "lxml")
# TODO: 遍历所有 a 标签,提取 href 和清洗后的文本,格式打印
for a in soup.select("a"):
href = a.get("href")
text = a.get_text(strip=True)
print(href, "=>", text)五、BS4 vs lxml/XPath
- BS4 胜在容错好、API 直观,新手友好。
- 纯 XPath(
lxml)在「按文字定位、向上找父节点」时更省事(见下一章 XPath)。 - 实战常组合:BS4 做主解析,遇到 BS4 不擅长的定位再切到
lxml的 XPath。
六、小结
BeautifulSoup(html, "lxml")解析;class参数要写class_。- 定位三件套:
find/find_all/select(CSS)。 - 取文本用
get_text(strip=True),取属性用get('href')。 - 节点树可上下遍历:
.parent、.children、.next_sibling。 - 练手:Level 1 靶站 用
select("tbody tr")抓 24 行。
本页底部「代码实战」让你在靶站上完成一次真实提取。