基于Scrapy框架的Python爬虫项目搭建与数据持久化实例

Jasper
Jasper
发布时间:2026-11-06| 7人浏览过
原创

本文详细讲解如何基于Scrapy框架搭建规范的Python网络爬虫工程,解析网页结构化数据,并通过Item Pipeline将采集结果持久化保存至SQLite数据库与JSON文件。

Python 爬虫工程实践

Scrapy 是 Python 领域工业级的异步网络爬虫框架,凭借 Twisted 异步网络库的事件驱动机制,能够在低资源消耗下实现高吞吐的数据采集。本文以抓取经典名言站点为实例,完整演示从零初始化 Scrapy 工程骨架、设计结构化 Item 实体、编写选择器与自动翻页爬虫,并通过自定义 Item Pipeline 将非结构化网页数据清洗并持久化至 SQLite 数据库与 JSON 文件的全过程。

基于Scrapy框架的Python爬虫项目搭建与数据持久化实例
图 0:基于 Scrapy 框架的爬虫系统层级流转与持久化总览

一、理解核心:Scrapy 核心架构与异步流转机制

在着手写代码之前,理解 Scrapy 内部组件的协作方式至关重要。很多初学者使用单纯的 requests 配合循环或线程池编写爬虫,当遇到海量链接调度、自动去重、失败重试与管道存储时,代码容易变得混乱脆弱。Scrapy 将这些高频爬虫任务拆分为高度解耦的核心组件:

  • 引擎 (Engine):框架的神经中枢,控制所有组件之间的数据信号流动,在特定动作发生时触发对应事件。
  • 调度器 (Scheduler):接收来自引擎的 HTTP 请求 (Request),按照优先级进行入队排序,并在内部通过请求指纹算法实现 URL 自动去重。
  • 下载器 (Downloader):基于 Twisted 异步获取网页 HTML 报文,并将封装好的响应对象 (Response) 返还给引擎。
  • 爬虫模块 (Spiders):开发者主要编写的核心业务代码,负责根据 XPath 或 CSS 选择器从 Response 中提取结构化数据 (Item) 或发掘下一页链接。
  • 数据管道 (Item Pipeline):负责接收爬虫产出的 Item,按顺序执行验证清洗、去重过滤以及持久化写入数据库或文件系统。
基于Scrapy框架的Python爬虫项目搭建与数据持久化实例
图 1:Scrapy 引擎为核心的异步请求调度与数据流转拓扑图

整个流转过程为单向闭环:Spider 产出初始 Request 提交给 Engine;Engine 将其送入 Scheduler 排队;Downloader 从 Scheduler 获取任务并异步拉取网页;返回的 Response 经过 Engine 投递回 Spider 的解析函数;Spider 提取出结构化的 Item 交给 Item Pipeline 落地存储,若提取出新链接则再次送入 Scheduler 进入下一轮循环。

二、环境准备与项目骨架搭建

进行 Scrapy 项目开发需要 Python 3.8 及以上环境。首先在终端中通过 pip 完成框架安装。为保证依赖纯净,建议在虚拟环境中操作。

pip install scrapy
示例输出:
Collecting scrapy
Installing collected packages: twisted, cryptography, cssselect, parsel, Scrapy
Successfully installed Scrapy-2.11.0

1. 创建项目工程

在工作目录中执行 scrapy startproject 命令,创建名为 quotes_crawler 的爬虫工程:

scrapy startproject quotes_crawler
示例输出:
New Scrapy project 'quotes_crawler', using template directory '.../site-packages/scrapy/templates/project'
You can start your first spider with:
    cd quotes_crawler
    scrapy genspider example example.com

2. 理解项目文件布局

进入创建好的项目文件夹,Scrapy 会自动生成规范的模块化文件结构:

quotes_crawler/
├── scrapy.cfg            # 项目部署根配置文件
└── quotes_crawler/       # Python 源码包
    ├── __init__.py
    ├── items.py          # 数据结构定义文件 (数据契约)
    ├── middlewares.py    # 爬虫与下载器中间件 (拦截修改 Request/Response)
    ├── pipelines.py      # 数据持久化处理管道 (存入文件或数据库)
    ├── settings.py       # 爬虫全局配置文件 (并发、请求头、管道启用等)
    └── spiders/          # 爬虫逻辑脚本存放目录
        └── __init__.py

3. 生成爬虫脚本

进入 quotes_crawler 目录,执行 genspider 命令以经典测试站点 quotes.toscrape.com 为目标生成爬虫模板:

cd quotes_crawler scrapy genspider quotes quotes.toscrape.com
示例输出:
Created spider 'quotes' using template 'basic' in module:
  quotes_crawler.spiders.quotes

三、数据建模与 Spider 解析逻辑编写

在 Scrapy 中,数据采集并非直接使用零散的 Python 字典,而是通过继承 scrapy.Item 建立明确的数据契约。这样做不仅能统一数据格式,还能在字段赋值错误时提前抛出异常,防止低级拼写错误。

基于Scrapy框架的Python爬虫项目搭建与数据持久化实例
图 2:Scrapy 爬虫项目搭建与核心编码四步实施路径

1. 定义 Item 实体字段

编辑 quotes_crawler/items.py 文件。本实例目标是提取名言文本 (text)、作者 (author) 以及标签列表 (tags):

import scrapy

class QuoteItem(scrapy.Item):
    # 名言正文
    text = scrapy.Field()
    # 作者名字
    author = scrapy.Field()
    # 标签数组
    tags = scrapy.Field()

2. 编写 Spider 网页解析与翻页跟进

打开 quotes_crawler/spiders/quotes.py。分析目标网页可知,每个名言块包裹在 <div class="quote"> 容器内。名言文本位于 span.text,作者位于 small.author,标签位于 a.tag,下一页链接位于 li.next > a::attr(href)。

使用 response.css 解析数据,并通过 response.follow 实现自动跟踪翻页:

import scrapy
from quotes_crawler.items import QuoteItem

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ["http://quotes.toscrape.com/"]

    def parse(self, response):
        # 遍历当前页面的所有名言块
        quote_elements = response.css("div.quote")
        for q in quote_elements:
            item = QuoteItem()
            # 提取文本并去除首尾特殊引号
            raw_text = q.css("span.text::text").get(default="").strip("“”")
            author = q.css("small.author::text").get(default="").strip()
            tags = q.css("div.tags a.tag::text").getall()

            item["text"] = raw_text
            item["author"] = author
            item["tags"] = tags

            # 将提取出的 item yield 给 Scrapy 引擎,进而流向 Pipeline
            yield item

        # 提取下一页链接并继续爬取
        next_page = response.css("li.next a::attr(href)").get()
        if next_page is not None:
            # response.follow 会自动将相对路径拼接为完整绝对 URL
            yield response.follow(next_page, callback=self.parse)

注意:在解析时优先使用 .get() 与 .getall() 方法,避免使用老旧的 .extract_first() 或 .extract()。.get(default="") 能有效避免解析不到元素时报 NoneType 异常。

四、数据持久化实现:从轻量导出到 SQLite 数据库

数据从网页提取出来后,最终目标是沉淀存储。Scrapy 提供了两种持久化路径:无需编写额外代码的内置 Feed Exports,以及应对复杂业务场景的 Item Pipeline。

基于Scrapy框架的Python爬虫项目搭建与数据持久化实例
图 3:Item Pipeline 多阶段数据清洗与持久化入库工作机制

1. 方式一:使用 Feed Exports 导出文件

对于快速测试或数据量适中的一次性任务,直接使用 Scrapy 内置的命令行参数 -o 即可导出标准格式文件:

scrapy crawl quotes -o quotes.json -s FEED_EXPORT_ENCODING=utf-8

该命令会自动将所有 yield 出的 Item 聚合保存为 UTF-8 编码的 JSON 文件。同样支持将后缀改为 .csv 或 .jsonl。

2. 方式二:编写自定义 Item Pipeline 写入 SQLite

在生产环境中,往往需要将数据实时落地到数据库中,并具备防重、过滤空数据和格式转换功能。Item Pipeline 是一个普通的 Python 类,通过实现以下三个标准钩子函数完成持久化周期管理:

  • open_spider(self, spider): 爬虫启动时触发一次,常用于建立数据库连接与初始化数据表。
  • process_item(self, item, spider): 每当 Spider yield 出一个 Item 时触发,在此执行校验、清洗与 SQL 插入。必须返回 item 或抛出 DropItem 异常。
  • close_spider(self, spider): 爬虫抓取结束时触发一次,常用于提交事务与安全关闭数据库连接。

打开 quotes_crawler/pipelines.py,编写完整的 SQLite 持久化管道:

import sqlite3
from scrapy.exceptions import DropItem

class QuoteValidationPipeline:
    # 第一阶段管道:校验与数据清洗
    def process_item(self, item, spider):
        # 校验正文是否有效
        if not item.get("text"):
            raise DropItem(f"发现无效名言数据,已丢弃: {item}")
        # 将标签列表转换为逗号分隔的字符串,便于关系型数据库存储
        if isinstance(item.get("tags"), list):
            item["tags_str"] = ",".join(item["tags"])
        else:
            item["tags_str"] = ""
        return item


class QuoteSqlitePipeline:
    # 第二阶段管道:SQLite 数据库持久化落地
    def __init__(self):
        self.db_name = "quotes_storage.db"
        self.connection = None
        self.cursor = None

    def open_spider(self, spider):
        # 建立数据库连接,并在本地创建 SQLite 文件
        self.connection = sqlite3.connect(self.db_name)
        self.cursor = self.connection.cursor()
        # 创建名言存储表结构
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS quotes_record (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                author TEXT NOT NULL,
                content TEXT NOT NULL UNIQUE,
                tags TEXT,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        self.connection.commit()
        spider.logger.info(f"SQLite 数据库 [{self.db_name}] 初始化就绪。")

    def process_item(self, item, spider):
        # 执行数据插入,使用 INSERT OR IGNORE 避免重复录入相同名言
        try:
            self.cursor.execute('''
                INSERT OR IGNORE INTO quotes_record (author, content, tags)
                VALUES (?, ?, ?)
            ''', (item["author"], item["text"], item.get("tags_str", "")))
            self.connection.commit()
        except sqlite3.Error as e:
            spider.logger.error(f"写入 SQLite 数据库失败: {e}")
        return item

    def close_spider(self, spider):
        # 安全提交与关闭数据库连接
        if self.connection:
            self.connection.commit()
            self.connection.close()
            spider.logger.info("SQLite 数据库连接已安全关闭。")

3. 在 settings.py 中激活 Pipeline 管道

定义完管道后,必须在 quotes_crawler/settings.py 中显式激活,否则 Scrapy 不会调用它们。在配置文件中找到 ITEM_PIPELINES 并修改如下:

ITEM_PIPELINES = {
    # 权重范围 0-1000,数值越小越优先执行
    "quotes_crawler.pipelines.QuoteValidationPipeline": 200,
    "quotes_crawler.pipelines.QuoteSqlitePipeline": 300,
}

此处 QuoteValidationPipeline 权重为 200,它会先接收到 Item 并清洗格式;清洗完毕返回给引擎,随后传递给权重为 300 的 QuoteSqlitePipeline 执行 SQL 插入。

五、配置调优、运行执行与结果验证

1. 爬虫策略关键配置 (settings.py)

在进行真实爬取前,需要对 settings.py 中的关键运行参数进行确认,保证爬虫稳定且合规运行:

配置项 推荐设定值 作用与原理解析
ROBOTSTXT_OBEY True 或 False 是否遵守目标站点的 robots.txt 协议。若为 True 且网站声明封禁,则爬虫会直接忽略抓取。
DOWNLOAD_DELAY 0.5 ~ 1.0 单域名下载延迟(秒)。限制发包频率,避免高并发直接打垮服务器或被防爬机制直接拉黑。
CONCURRENT_REQUESTS 16 (默认) Scrapy 下载器并发请求总数。生产环境中需结合网络带宽与目标服务器承载力综合权衡。
DEFAULT_REQUEST_HEADERS 规范浏览器 User-Agent 伪装正常浏览器访问指纹,防止被反爬系统凭借默认的 Scrapy/2.x 特征直接阻断。
# settings.py 关键修改片段示例
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 0.5
FEED_EXPORT_ENCODING = "utf-8"

2. 执行爬取命令

在项目根目录下启动爬虫:

scrapy crawl quotes
运行日志输出节选:
2026-11-01 03:10:00 [scrapy.core.engine] INFO: Spider opened
2026-11-01 03:10:00 [quotes_crawler.pipelines] INFO: SQLite 数据库 [quotes_storage.db] 初始化就绪。
2026-11-01 03:10:01 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/>
2026-11-01 03:10:01 [quotes] DEBUG: Scraped from <200 http://quotes.toscrape.com/>: {'author': 'Albert Einstein', ...}
...
2026-11-01 03:10:08 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'item_scraped_count': 100,
 'response_received_count': 10,
 'downloader/request_count': 10}
2026-11-01 03:10:08 [quotes_crawler.pipelines] INFO: SQLite 数据库连接已安全关闭。
2026-11-01 03:10:08 [scrapy.core.engine] INFO: Spider closed (finished)

3. 验证数据库落库结果

使用 Python 自带的 sqlite3 命令行工具或脚本查询刚才生成的 quotes_storage.db 文件,确认持久化是否成功:

python3 -c "import sqlite3; conn = sqlite3.connect('quotes_storage.db'); print('已成功落库条数:', conn.execute('SELECT count(*) FROM quotes_record').fetchone()[0])"
示例输出:
已成功落库条数: 100
基于Scrapy框架的Python爬虫项目搭建与数据持久化实例
图 4:Scrapy 项目全流程构建、数据管道流转与生产环境关键保障要素全景总结

至此,一个从页面异步抓取、结构化数据清洗、多层过滤到最终入库 SQLite 数据库的完整 Scrapy 爬虫项目便搭建完成。在后续更复杂的项目中,你可以直接复用这套工程规范,并在 pipelines.py 中无缝扩展 MySQL 连接池、MongoDB 驱动或 Elasticsearch 索引引擎。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。