前言
在爬虫开发中,拿到网页HTML源码后,需要完成解析、提取文本、修改节点、过滤标签、HTML转换等工作。BeautifulSoup4(简称bs4)是Python最常用的HTML/XML解析库,它可以把杂乱不规范的网页HTML修复为DOM树,相比手写正则解析HTML,稳定性更强,容错能力高,适合处理真实互联网上各式各样的脏网页。
注意:BeautifulSoup本身只是解析封装,底层需要依赖解析器,常用两种:
html.parser:Python内置,无需额外安装,容错一般;lxml:速度快,容错强,生产环境优先推荐,需要pip安装。
一、安装依赖
# 安装bs4
pip install beautifulsoup4
# 推荐同时安装lxml解析器(性能更好)
pip install lxml
二、基础使用:加载HTML
1. 从字符串加载
from bs4 import BeautifulSoup
html_doc = """
<html>
<head><title>测试页面</title></head>
<body>
<div class="item">
<h2>标题1</h2>
<p class="desc">这是描述文本</p>
</div>
</body>
</html>
"""
# 使用lxml解析器
soup = BeautifulSoup(html_doc, "lxml")
# 格式化输出html
print(soup.prettify())
2. 结合requests爬虫,解析网页响应
import requests
from bs4 import BeautifulSoup
resp = requests.get("[https://example.com](https://example.com)")
# 直接传入文本
soup = BeautifulSoup(resp.text, "lxml")
小提示:遇到UTF‑8 BOM网页,如果乱码,可以先处理bytes再解码:
content = resp.content
if content.startswith(b"\xef\xbb\xbf"):
content = content[3:]
soup = BeautifulSoup(content.decode("utf‑8‑sig", errors="replace"), "lxml")
三、节点查找提取数据(核心API)
1. find():查找第一个匹配节点
# 根据标签名
title_tag = soup.find("title")
print(title_tag.text)
# 根据class类名
div_tag = soup.find("div", class_="item")
# 根据id
soup.find(id="main")
⚠️ class是Python关键字,bs4中使用参数名
class_带下划线。
2. find_all():查找全部匹配节点,返回列表
# 获取所有p标签
p_list = soup.find_all("p")
# 获取所有class=desc的p标签
p_desc_list = soup.find_all("p", class_="desc")
# 限制返回最多2条结果
soup.find_all("p", class_="desc", limit=2)
3. CSS选择器 select / select_one
熟悉css选择器的话优先用这个,写起来简洁。
-
select_one():匹配第一个,没有返回None -
select():匹配全部,返回列表.代表class,#代表id
item_div = soup.select_one(".item")
all_p = soup.select(".item p")for p in all_p:
print(p.get_text(strip=True))
四、获取文本、属性
获取节点文本
tag = soup.find("p", class_="desc")
# .text 获取所有拼接文本,包含子节点文字
print(tag.text)
# get_text(),strip=True自动去除前后空白、换行
print(tag.get_text(strip=True))
# 分割文本,使用分隔符拼接子节点文本
print(tag.get_text(strip=True, separator=" "))
获取标签属性
a_tag = soup.find("a")
href = a_tag.get("href") # 推荐,属性不存在返回None,不会抛异常
# 不推荐:a_tag["href"] 不存在属性直接抛KeyError
# 获取全部属性字典
attr_dict = a_tag.attrs
print(attr_dict)
五、修改HTML DOM(增删改节点)
适合场景:修改网页片段、转换HTML、清理无用标签。
1. 创建新节点
from bs4 import BeautifulSoup, NavigableString, Tag
new_tag = soup.new_tag("td")
new_tag.string = "单元格内容"
2. 添加子节点
div = soup.find("div", class_="item")
div.append(new_tag) # 末尾追加节点
3. 删除节点
tag = soup.find("script")
if tag:
tag.decompose() # 彻底移除节点以及内部所有内容
4. 替换节点内容
tag.string = "新的文字内容"
5. 输出处理完成后的HTML字符串
out_html = soup.prettify() # 格式化带换行缩进
raw_html = str(soup) # 紧凑输出
六、实战示例1:清理网页,移除script、style
爬虫预处理网页,清除js、css标签,减少干扰:
def clean_html(html_str: str):
soup = BeautifulSoup(html_str, "lxml")
# 删除不需要的标签
for bad in soup(["script", "style", "noscript"]):
bad.decompose()
return soup.prettify()
七、实战示例2:div伪表格转table(对应你之前的业务场景)
把bootstrap div栅格伪表格,用bs4实现转为原生table,和之前lxml版本效果一致
from bs4 import BeautifulSoup
def bs_div_to_table(html_str: str) -> str:
soup = BeautifulSoup(html_str, "lxml")
table = soup.new_tag("table", border="1", cellpadding="6", cellspacing="0", style="border‑collapse:collapse;width:100%;")
thead = soup.new_tag("thead")
tbody = soup.new_tag("tbody")
table.append(thead)
table.append(tbody)
# 解析表头
header_box = soup.select_one('div.row.structure .boxs')
if header_box:
tr_head = soup.new_tag("tr")
for col_div in header_box.select("> div"):
txt = col_div.get_text(strip=True)
th = soup.new_tag("th")
th.string = txt
tr_head.append(th)
thead.append(tr_head)
# 解析所有数据行
rows = soup.select("div.structurewords")
for row_div in rows:
tr = soup.new_tag("tr")
for cell_div in row_div.select("> div"):
cell_txt = cell_div.get_text(strip=True)
td = soup.new_tag("td")
td.string = cell_txt
tr.append(td)
tbody.append(tr)
full_soup = BeautifulSoup("""<!DOCTYPE html>
<html lang="zh‑CN">
<head><meta charset="UTF‑8"><title>表格预览</title></head>
<body></body>
</html>""", "lxml")
full_soup.body.append(table)
return full_soup.prettify()
八、BeautifulSoup常见坑点
- 不要用正则代替解析库:HTML标签嵌套、属性顺序变化,正则极易解析失败;
find()找不到返回None,调用.text会抛AttributeError,要做判空;- 获取属性优先用
.get("xxx"),不要直接下标["xxx"],防止属性缺失抛异常; prettify()会增加换行缩进,如果入库存储不需要格式化,直接用str(soup);- 网页不规范、残缺标签,
lxml解析器修复能力比内置html.parser更强; - bs4适合解析操作DOM,大规模抓取解析性能弱于lxml,追求速度优先选lxml。
小结
BeautifulSoup4 封装简单友好,适合大多数爬虫HTML解析、清洗、修改DOM场景。
- 简单提取:优先使用
select_one()/select()CSS选择器; - 清理网页:
decompose()删除无用标签; - 改造HTML结构:
new_tag()创建节点、append()组装DOM。
对比:lxml性能更高,适合高并发爬虫;bs4语法更通俗易懂,适合快速开发、调试。