Python 网页数据爬取入门教程:requests + BeautifulSoup 从解析到保存

Python 网页数据爬取入门教程:requests + BeautifulSoup 从解析到保存

网络爬虫的核心工作其实并不复杂:发送请求、获取网页、解析 HTML、提取需要的数据、保存结果。对于 Python 初学者来说,requests + beautifulsoup4 是非常适合入门的一组工具。

本文会从基础概念讲起,介绍如何解析 HTML、查找标签、提取标题与链接、批量抓取网页数据,并把结果保存为 txt 和 Excel 文件。最后也会补充一些基础反爬说明,帮助你写出更稳定、更合规的爬虫程序。

一、requests + BeautifulSoup 基本介绍

1. requests 是什么

requests 是 Python 中常用的 HTTP 请求库,用它可以访问网页、接口或下载文件。

常见用法:

python 复制代码
import requests

response = requests.get("https://example.com")
print(response.status_code)
print(response.text)

其中:

  • requests.get():发送 GET 请求
  • response.status_code:HTTP 状态码,例如 200 表示成功
  • response.text:网页文本内容,通常是 HTML

2. BeautifulSoup 是什么

BeautifulSoup 来自 beautifulsoup4 库,主要作用是解析 HTML 或 XML 文档,并提供方便的标签查找方法。

安装命令:

powershell 复制代码
pip install requests beautifulsoup4 openpyxl

其中:

  • requests:负责获取网页
  • beautifulsoup4:负责解析 HTML
  • openpyxl:负责写入 Excel 文件

导入方式:

python 复制代码
import requests
from bs4 import BeautifulSoup

二、HTML 解析基础

网页本质上是一段 HTML 文本。比如下面这段简单 HTML:

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>示例页面</title>
</head>
<body>
    <h1>文章列表</h1>
    <a href="https://example.com/post/1">第一篇文章</a>
    <a href="https://example.com/post/2">第二篇文章</a>
</body>
</html>

我们可以用 BeautifulSoup 把 HTML 字符串解析成一个可查询的对象:

python 复制代码
from bs4 import BeautifulSoup

html = """
<html>
<head><title>示例页面</title></head>
<body>
    <h1>文章列表</h1>
    <a href="https://example.com/post/1">第一篇文章</a>
    <a href="https://example.com/post/2">第二篇文章</a>
</body>
</html>
"""

soup = BeautifulSoup(html, "html.parser")

print(soup.title.text)
print(soup.h1.text)

输出结果:

text 复制代码
示例页面
文章列表

这里的 "html.parser" 是 Python 标准库自带的 HTML 解析器,入门阶段直接使用它即可。

三、查找标签

BeautifulSoup 常用的查找方法有:

  • find():查找第一个匹配标签
  • find_all():查找所有匹配标签
  • select():使用 CSS 选择器查找
  • select_one():使用 CSS 选择器查找第一个匹配项

1. 使用 find

python 复制代码
title_tag = soup.find("title")
print(title_tag.text)

2. 使用 find_all

python 复制代码
links = soup.find_all("a")

for link in links:
    print(link.text)

3. 使用 CSS 选择器

如果 HTML 中有 class:

html 复制代码
<div class="article">
    <a href="/post/1">第一篇文章</a>
</div>

可以这样查找:

python 复制代码
articles = soup.select(".article a")

for article in articles:
    print(article.text)

CSS 选择器常见写法:

  • a:查找所有 <a> 标签
  • .article:查找 class="article" 的元素
  • #main:查找 id="main" 的元素
  • .article a:查找 .article 内部的所有 <a> 标签

四、提取标题与链接

下面演示从网页中提取所有链接的文本和地址。

python 复制代码
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin


url = "https://example.com"

headers = {
    "User-Agent": "Mozilla/5.0"
}

response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()

soup = BeautifulSoup(response.text, "html.parser")

for a_tag in soup.find_all("a"):
    title = a_tag.get_text(strip=True)
    href = a_tag.get("href")

    if not title or not href:
        continue

    full_url = urljoin(url, href)
    print(title, full_url)

代码说明:

  • get_text(strip=True):提取标签文本,并去掉首尾空白
  • get("href"):获取 <a> 标签的 href 属性
  • urljoin():把相对链接转换成完整链接
  • raise_for_status():如果请求失败,抛出异常,方便发现问题

五、批量抓取网页数据

很多网站的列表页会按页码变化,比如:

text 复制代码
https://example.com/page/1
https://example.com/page/2
https://example.com/page/3

批量抓取时,可以先写一个函数抓取单页,再循环多个页面。

python 复制代码
import time
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin


def fetch_html(url):
    headers = {
        "User-Agent": "Mozilla/5.0"
    }
    response = requests.get(url, headers=headers, timeout=10)
    response.raise_for_status()
    response.encoding = response.apparent_encoding
    return response.text


def parse_links(html, base_url):
    soup = BeautifulSoup(html, "html.parser")
    results = []

    for a_tag in soup.find_all("a"):
        title = a_tag.get_text(strip=True)
        href = a_tag.get("href")

        if not title or not href:
            continue

        results.append({
            "title": title,
            "url": urljoin(base_url, href)
        })

    return results


all_results = []

for page in range(1, 4):
    page_url = f"https://example.com/page/{page}"
    print(f"正在抓取:{page_url}")

    try:
        html = fetch_html(page_url)
        page_results = parse_links(html, page_url)
        all_results.extend(page_results)
    except requests.RequestException as error:
        print(f"抓取失败:{error}")

    time.sleep(1)

print(f"共抓取到 {len(all_results)} 条数据")

这里加入了 time.sleep(1),表示每抓取一页后暂停 1 秒。这样可以降低访问频率,也能减少被网站限制的概率。

六、保存为 txt 和 Excel

抓取到数据之后,常见保存方式有两种:

  • 保存为 txt,方便快速查看
  • 保存为 Excel,方便筛选、排序和分析

1. 保存为 txt

python 复制代码
def save_to_txt(data, file_path):
    with open(file_path, "w", encoding="utf-8") as file:
        for item in data:
            file.write(f"标题:{item['title']}\n")
            file.write(f"链接:{item['url']}\n")
            file.write("-" * 60 + "\n")

2. 保存为 Excel

python 复制代码
from openpyxl import Workbook


def save_to_excel(data, file_path):
    workbook = Workbook()
    sheet = workbook.active
    sheet.title = "网页数据"

    sheet.append(["序号", "标题", "链接"])

    for index, item in enumerate(data, start=1):
        sheet.append([index, item["title"], item["url"]])

    workbook.save(file_path)

七、反爬基础说明

初学爬虫时,经常会遇到这些情况:

  • 请求返回 403
  • 页面内容为空
  • 浏览器能看到数据,代码抓不到
  • 短时间访问太多后被限制
  • 数据由 JavaScript 动态加载

一些基础处理方式:

1. 设置 User-Agent

很多网站会检查请求头,简单设置 User-Agent 可以让请求更接近普通浏览器访问。

python 复制代码
headers = {
    "User-Agent": "Mozilla/5.0"
}

2. 控制请求频率

不要高频访问页面,建议每次请求之间加入延迟。

python 复制代码
import time

time.sleep(1)

3. 设置超时时间

避免某个请求长时间卡住。

python 复制代码
requests.get(url, timeout=10)

4. 处理异常

网络请求可能失败,所以要用 try...except 做异常处理。

python 复制代码
try:
    response = requests.get(url, timeout=10)
    response.raise_for_status()
except requests.RequestException as error:
    print(f"请求失败:{error}")

5. 尊重网站规则

爬虫不是"能抓就抓"。实际开发中要注意:

  • 遵守网站的 robots.txt 和服务条款
  • 不抓取隐私数据、账号数据和敏感数据
  • 不对网站造成高频压力
  • 优先使用网站提供的公开 API
  • 只在学习、测试或授权范围内抓取数据

这些比代码技巧更重要。

八、完整代码演示

下面是一份完整示例代码。它会批量访问多个页面,提取页面中的标题和链接,并保存为 txt 与 Excel。

为了方便初学者理解,示例使用通用 HTML 链接提取逻辑。实际项目中,你需要根据目标网页的 HTML 结构调整选择器。

保存为 crawler_demo.py

python 复制代码
import time
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook


HEADERS = {
    "User-Agent": "Mozilla/5.0"
}


def fetch_html(url):
    """请求网页并返回 HTML 文本。"""
    response = requests.get(url, headers=HEADERS, timeout=10)
    response.raise_for_status()
    response.encoding = response.apparent_encoding
    return response.text


def parse_title_and_links(html, base_url):
    """从 HTML 中提取页面标题和所有链接。"""
    soup = BeautifulSoup(html, "html.parser")

    page_title = ""
    if soup.title and soup.title.text:
        page_title = soup.title.get_text(strip=True)

    results = []

    for a_tag in soup.find_all("a"):
        link_text = a_tag.get_text(strip=True)
        href = a_tag.get("href")

        if not link_text or not href:
            continue

        results.append({
            "page_title": page_title,
            "link_text": link_text,
            "url": urljoin(base_url, href)
        })

    return results


def crawl_pages(urls, delay=1):
    """批量抓取多个网页。"""
    all_results = []

    for url in urls:
        print(f"正在抓取:{url}")

        try:
            html = fetch_html(url)
            page_results = parse_title_and_links(html, url)
            all_results.extend(page_results)
            print(f"本页提取到 {len(page_results)} 条链接")
        except requests.RequestException as error:
            print(f"请求失败:{url},原因:{error}")

        time.sleep(delay)

    return all_results


def save_to_txt(data, file_path):
    """保存数据到 txt 文件。"""
    with open(file_path, "w", encoding="utf-8") as file:
        for index, item in enumerate(data, start=1):
            file.write(f"序号:{index}\n")
            file.write(f"页面标题:{item['page_title']}\n")
            file.write(f"链接文本:{item['link_text']}\n")
            file.write(f"链接地址:{item['url']}\n")
            file.write("-" * 60 + "\n")


def save_to_excel(data, file_path):
    """保存数据到 Excel 文件。"""
    workbook = Workbook()
    sheet = workbook.active
    sheet.title = "爬取结果"

    sheet.append(["序号", "页面标题", "链接文本", "链接地址"])

    for index, item in enumerate(data, start=1):
        sheet.append([
            index,
            item["page_title"],
            item["link_text"],
            item["url"]
        ])

    sheet.column_dimensions["A"].width = 8
    sheet.column_dimensions["B"].width = 30
    sheet.column_dimensions["C"].width = 30
    sheet.column_dimensions["D"].width = 60

    workbook.save(file_path)


def main():
    urls = [
        "https://example.com",
        "https://www.python.org"
    ]

    results = crawl_pages(urls, delay=1)

    if not results:
        print("没有提取到数据。")
        return

    save_to_txt(results, "crawler_result.txt")
    save_to_excel(results, "crawler_result.xlsx")

    print(f"抓取完成,共 {len(results)} 条数据")
    print("已保存:crawler_result.txt")
    print("已保存:crawler_result.xlsx")


if __name__ == "__main__":
    main()

九、运行说明

1. 安装依赖

在命令提示符或 PowerShell 中执行:

powershell 复制代码
pip install requests beautifulsoup4 openpyxl

2. 保存代码

把完整代码保存为:

text 复制代码
crawler_demo.py

3. 运行程序

powershell 复制代码
python crawler_demo.py

运行完成后,会在当前目录生成:

text 复制代码
crawler_result.txt
crawler_result.xlsx

4. 修改目标网页

如果你要抓取其他网页,可以修改:

python 复制代码
urls = [
    "https://example.com",
    "https://www.python.org"
]

如果目标网页结构比较明确,例如文章标题都在 .article-title a 中,可以把解析逻辑改成:

python 复制代码
for a_tag in soup.select(".article-title a"):
    link_text = a_tag.get_text(strip=True)
    href = a_tag.get("href")

这就是 BeautifulSoup 的常见使用方式:先观察 HTML 结构,再写对应选择器。

十、总结

本文完成了 Python 网络爬虫入门的核心流程:

  • 使用 requests 获取网页 HTML
  • 使用 BeautifulSoup 解析 HTML
  • 使用 findfind_allselect 查找标签
  • 提取网页标题、链接文本和链接地址
  • 批量抓取多个网页
  • 将结果保存为 txt 和 Excel
  • 理解基础反爬与合规注意事项

对初学者来说,最重要的不是一上来写复杂爬虫,而是先掌握"请求、解析、提取、保存"这条主线。等这个流程熟练之后,再继续学习登录态、分页接口、动态渲染页面、代理、任务队列和数据清洗等进阶内容会更稳。

相关推荐
kaikaile199517 小时前
基于 MATLAB 的3D 蒙特卡洛光子传输模拟
开发语言·matlab·3d
我是唐青枫17 小时前
C#.NET YARP 认证授权实战:在网关层统一接入 JWT
开发语言·c#·.net
次元工程师!17 小时前
LangFlow开发(一)—安装和部署
git·python·大模型·langflow
故事和你9117 小时前
洛谷-【数据结构2-2】线段树2
开发语言·数据结构·算法·动态规划·图论
故事和你9117 小时前
洛谷-【数据结构2-2】线段树1
开发语言·javascript·数据结构·算法·动态规划·图论
鸠摩智首席音效师17 小时前
如何在 Bash 中通过 Amazon SES 发送电子邮件 ?
开发语言·bash
deephub17 小时前
Feature Engineering 实战:Pandas + Scikit-learn的机器学习特征工程的完整代码示例
人工智能·python·机器学习·pandas·scikit-learn
code_pgf17 小时前
Python `asyncio` 与 C++ Fiber 的原理与逻辑分析
c++·人工智能·python
张二娃同学17 小时前
第03篇_CNN图像识别入门
人工智能·python·神经网络·cnn
~|Bernard|17 小时前
五,go语言的内存管理
开发语言·后端·golang