python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python BeautifulSoup抓取和解析网页数据

Python使用BeautifulSoup抓取和解析网页数据的入门教程

作者:yuanpan

文章介绍了Python中BeautifulSoup库用于解析HTML和提取网页数据的基本使用方法,包括安装依赖、基础用法、常用API以及实际操作示例,文中详细解释了BeautifulSoup与requests的关系,如何抓取和解析网页数据,并提供了常见错误和注意事项,需要的朋友可以参考下

很多 Python 初学者学完基础语法之后,都会很自然地遇到一个问题:

我能不能把网页里的内容提取下来,变成自己能处理的数据?

比如:

这时候,BeautifulSoup 往往就是最适合入门的工具之一。

它不像大型爬虫框架那样一上来就有很多工程化概念,也不像正则表达式那样容易把人绕晕。它做的事情很纯粹:

帮你解析 HTML,然后从中提取你真正需要的数据。

如果你现在正在学习 Python,又想快速上手网页数据抓取,这篇文章会非常适合你。我们会从 0 开始讲清楚:

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 解析成一个结构化对象,然后你就可以像查树节点一样去找:

这也是它名字里 Soup 的感觉所在。原本很乱的网页源码,会被它整理成更容易“舀出来”的结构。

2. BeautifulSoup 和 requests 是什么关系

很多新手刚接触网页抓取时,最容易混淆这两个库。

其实职责非常清楚:

所以它们常常一起出现:

  1. 先用 requests.get() 拿到 HTML
  2. 再用 BeautifulSoup() 把 HTML 解析成对象
  3. 最后用各种选择器提取需要的数据

一句话记住:

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.h1find()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")

常见写法:

在很多实际项目中,select()select_one() 会比 find() 更顺手。

5.4get_text()和get()

提取文本:

text = title.get_text(strip=True)

提取属性:

href = link.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()

这个示例故意分成两部分:

学习这类东西时,建议你也这么练:

先会“解析”,再会“抓取”,最后再把两者组合。

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")

当然能找到一堆链接,但里面往往混着:

最后数据会很乱。

更好的做法是:

  1. 先找到列表区域
  2. 再在这个区域里找标题、链接、作者、时间

也就是说,尽量从:

soup.select(".article-card")

这种“按块定位”的方式入手,而不是全页面乱抓。

9. BeautifulSoup 常见解析器怎么选

创建对象时你会看到第二个参数:

BeautifulSoup(html, "html.parser")

这里指定的是解析器。

常见的有三个:

如果你是初学者:

先跑通流程,比一开始纠结性能更重要。

10. 为什么有时抓不到你在浏览器里看到的内容

这是 BeautifulSoup 初学者非常容易遇到的坑。

你在浏览器里明明看到了内容,但 requests.get() 拿回来的 HTML 里却没有。

原因通常是:

页面的数据是通过 JavaScript 动态加载的。

也就是说,浏览器打开页面后,还会继续执行 JS,再向接口请求数据,最后才把内容渲染出来。

requests 拿到的只是最初的 HTML。

这时候 BeautifulSoup 没问题,问题在于你抓到的输入源就不完整。

遇到这种情况,常见思路有两个:

所以要记住:

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 非常适合下面这些任务:

比如:

如果你只是想先把网页数据提下来,再做后续分析处理,BeautifulSoup 是一个很好的起点。

13. BeautifulSoup 和 Scrapy 该怎么选

这个问题很多人都会问。

可以这样理解:

如果你的需求是:

那么 requests + BeautifulSoup 会更轻、更直接。

如果你的需求是:

那通常就要考虑 Scrapy 了。

所以 BeautifulSoup 并不是“低配版 Scrapy”,而是更适合入门和轻量场景的工具。

14. 给初学者的学习建议

如果你想真正学会 BeautifulSoup,不建议只看语法。

更好的学习顺序是:

  1. 先用本地 HTML 字符串练 find()find_all()select()
  2. 再学 requests.get() 把网页拿下来
  3. 再自己挑一个结构简单的页面练手
  4. 把提取结果整理成字典或列表
  5. 最后导出成 JSON、CSV 或写入数据库

你会发现,真正的能力不是“会几个 API”,而是:

看到一个网页,能快速判断该从哪里切入提取数据。

15. 总结

BeautifulSoup 是 Python 生态里非常经典、也非常适合新手入门的网页解析库。

它最大的价值不是“语法多高级”,而是把网页提取这件事变得直观了很多。

记住这套组合最核心的分工:

如果你正在学习 Python,又希望尽快做出一些“能解决实际问题”的小工具,那么 BeautifulSoup 非常值得你亲手写一遍。

先从本地 HTML 开始,跑通选择器,再去抓真实网页,你的进步会快很多。

以上就是Python使用BeautifulSoup抓取和解析网页数据的入门教程的详细内容,更多关于Python BeautifulSoup抓取和解析网页数据的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文