如何使用Python的BeautifulSoup库来处理HTML

前言

在爬虫开发中,拿到网页HTML源码后,需要完成解析、提取文本、修改节点、过滤标签、HTML转换等工作。BeautifulSoup4(简称bs4)是Python最常用的HTML/XML解析库,它可以把杂乱不规范的网页HTML修复为DOM树,相比手写正则解析HTML,稳定性更强,容错能力高,适合处理真实互联网上各式各样的脏网页。

注意:BeautifulSoup本身只是解析封装,底层需要依赖解析器,常用两种:

  1. html.parser:Python内置,无需额外安装,容错一般;
  2. 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常见坑点

  1. 不要用正则代替解析库:HTML标签嵌套、属性顺序变化,正则极易解析失败;
  2. find()找不到返回None,调用.text会抛AttributeError,要做判空;
  3. 获取属性优先用.get("xxx"),不要直接下标["xxx"],防止属性缺失抛异常;
  4. prettify()会增加换行缩进,如果入库存储不需要格式化,直接用str(soup)
  5. 网页不规范、残缺标签,lxml解析器修复能力比内置html.parser更强;
  6. bs4适合解析操作DOM,大规模抓取解析性能弱于lxml,追求速度优先选lxml。

小结

BeautifulSoup4 封装简单友好,适合大多数爬虫HTML解析、清洗、修改DOM场景。

  • 简单提取:优先使用select_one() / select() CSS选择器;
  • 清理网页:decompose()删除无用标签;
  • 改造HTML结构:new_tag()创建节点、append()组装DOM。

对比:lxml性能更高,适合高并发爬虫;bs4语法更通俗易懂,适合快速开发、调试。

相关推荐
傻啦嘿哟44 分钟前
某新闻平台爬虫:爬取各频道新闻,分析媒体传播规律
python
鹿角片ljp1 小时前
Prompt Cache、Token 成本与 Plan Compiler 的工程设计
java·python·算法
麻雀飞吧9 小时前
先判断工具用来学习、开发还是执行
人工智能·python
人邮异步社区10 小时前
学习Python的最佳学习路径是什么?
python·程序员
troy12812 小时前
Python 基础语法(九):Django/Flask/FastAPI 三大 Web 框架详细对比解析
python·jupyter·django·flask·github·fastapi
jzshmyt12 小时前
我用 Python 从零“生成“了一个宇宙,然后让它观察自己(v14)
人工智能·pytorch·python·numpy·matplotlib·空间计算·scipy
用户83562907805114 小时前
使用 Python 将 DOCX 转换为 Markdown
后端·python
小玮看世界14 小时前
[Python]ADAS工程实战(三):多传感器扇区统计疑难点全解——归一化、跨边界、去重与置信度
python
TomEval15 小时前
【测AI】第02篇:Python 环境搭建与基础语法速通
人工智能·python·功能测试·aigc