Python Scrapy 爬虫实战进阶系列(一):轻量化数据存储 - 数据精准写入 SQLite 数据库
前言
在 Python 爬虫开发领域中,Scrapy 作为高性能、高可扩展性的异步爬虫框架,是行业内采集结构化数据的首选工具。在中小型爬虫项目、本地数据采集、轻量化数据存储场景中,SQLite 无需独立服务、单文件存储、原生兼容 Python 的特性,完美匹配 Scrapy 爬虫的轻量化部署需求。本系列第一篇将从零到一实现 Scrapy 爬虫数据写入 SQLite 数据库的完整方案,涵盖环境搭建、项目创建、数据建模、管道开发、数据入库、数据校验全流程,同时深度解析核心原理,为后续进阶开发奠定基础。
本文涉及的核心依赖与官方资源如下,可直接点击访问:
- Scrapy 官方文档:Scrapy 框架权威使用指南
- Python 官方下载:Python 运行环境,3.8 及以上版本最佳
- SQLite 官方文档:轻量化关系型数据库官方资料
- SQLiteStudio 可视化工具:免费 SQLite 数据可视化管理工具
本文采用专家级书面语,结合实战案例、原理剖析、代码详解,覆盖 Scrapy+SQLite 整合全流程,适合具备 Python 基础、爬虫入门开发者学习,可直接应用于生产级轻量化爬虫项目。
一、开发环境准备与依赖安装
1.1 环境要求
本项目基于 Python 3.8 + 开发,兼容 Windows、macOS、Linux 全平台,无特殊硬件要求,核心依赖仅包含 Scrapy 框架,Python 内置sqlite3库无需额外安装。
1.2 核心依赖安装
打开系统终端(Windows 为 CMD/PowerShell,macOS/Linux 为 Terminal),执行以下命令安装 Scrapy 框架:
bash
运行
# 安装Scrapy最新稳定版 pip install scrapy # 验证安装是否成功 scrapy version执行成功后,终端会输出 Scrapy、Twisted、lxml 等依赖版本信息,证明环境搭建完成。
1.3 依赖核心说明
- Scrapy:异步爬虫框架,提供请求发送、数据解析、管道处理、中间件等全功能组件,是本项目的核心框架。
- sqlite3:Python 内置标准库,无需单独安装,提供 SQLite 数据库的连接、创建表、增删改查等所有操作。
- SQLiteStudio(可选):可视化工具,用于查看爬虫入库后的数据,提升开发调试效率。
二、Scrapy 项目创建与基础结构解析
2.1 创建 Scrapy 项目
在本地创建一个空文件夹(建议命名为scrapy_sqlite_demo),进入文件夹后执行 Scrapy 创建命令:
bash
运行
# 创建爬虫项目 scrapy startproject sqlite_spider # 进入项目目录 cd sqlite_spider执行完成后,会自动生成标准的 Scrapy 项目结构,这是 Scrapy 官方规定的模块化结构,所有开发工作均在此结构内完成。
2.2 项目核心文件作用详解
为了让开发者清晰理解每个文件的功能,通过表格形式详细说明:
表格
| 文件 / 文件夹名称 | 核心作用 |
|---|---|
sqlite_spider/ | 项目核心代码包,所有爬虫逻辑、管道、配置均在此处 |
__init__.py | Python 包标识文件,无业务代码,用于标识目录为 Python 包 |
items.py | 数据建模文件,定义爬虫采集的字段结构,统一数据格式 |
middlewares.py | 中间件文件,用于处理请求、响应、异常等扩展逻辑 |
pipelines.py | 管道文件,核心,用于数据处理、数据入库、数据清洗 |
settings.py | 项目配置文件,配置并发数、请求头、管道、延迟等核心参数 |
spiders/ | 爬虫文件夹,存放所有爬虫脚本,一个栏目 / 站点对应一个爬虫文件 |
scrapy.cfg | 项目部署配置文件,用于项目打包、部署、远程运行 |
2.3 创建爬虫文件
在spiders文件夹下创建爬虫脚本,本案例以采集公开图书榜单数据为例,创建爬虫:
bash
运行
# 创建爬虫,名称:book_spider,允许域名:book.douban.com scrapy genspider book_spider book.douban.com执行后,spiders文件夹下会生成book_spider.py爬虫文件,后续数据解析逻辑在此文件编写。
三、数据建模:定义 Item 数据结构
3.1 Item 作用原理
Item 是 Scrapy 框架中数据容器,作用是统一爬虫采集的数据格式,避免不同爬虫、不同字段导致的数据混乱。爬虫解析的数据先封装到 Item 对象中,再传递给 Pipeline 进行处理,这是 Scrapy 数据流转的核心规范。
3.2 编写 Item 代码
打开items.py文件,定义图书数据的字段,包含图书名称、作者、出版社、出版日期、价格、评分,代码如下:
python
运行
# Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class SqliteSpiderItem(scrapy.Item): """ 图书数据Item,定义爬虫采集的所有字段 字段名称与数据库表字段一一对应,便于数据入库 """ # 图书名称 book_name = scrapy.Field() # 图书作者 book_author = scrapy.Field() # 出版社 book_publisher = scrapy.Field() # 出版日期 publish_date = scrapy.Field() # 图书价格 book_price = scrapy.Field() # 图书评分 book_score = scrapy.Field()3.3 Item 定义规则
- 所有字段必须使用
scrapy.Field()定义,无类型限制,兼容字符串、数字、日期等所有数据类型。 - 字段名称建议与数据库表字段保持一致,减少管道中的字段映射工作。
- 一个 Item 对应一类数据,多类数据可创建多个 Item 类。
四、SQLite 数据库表设计与创建
4.1 SQLite 核心原理
SQLite 是嵌入式关系型数据库,核心特性:
- 无独立服务进程,数据存储在单个
.db文件中,拷贝文件即可迁移数据库。 - 支持标准 SQL 语法,与 MySQL、Oracle 使用逻辑一致,学习成本低。
- 原生支持 Python,无需配置连接信息,适合轻量化爬虫项目。
- 单文件存储,无需部署数据库环境,一键启动爬虫即可自动创建数据库。
4.2 数据库表设计
根据 Item 定义的字段,设计book_info数据表,表结构如下:
表格
| 字段名 | 数据类型 | 约束 | 说明 |
|---|---|---|---|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | 主键,自增,唯一标识 |
| book_name | TEXT | NOT NULL | 图书名称,非空 |
| book_author | TEXT | NULL | 图书作者,可为空 |
| book_publisher | TEXT | NULL | 出版社,可为空 |
| publish_date | TEXT | NULL | 出版日期,可为空 |
| book_price | TEXT | NULL | 图书价格,可为空 |
| book_score | REAL | NULL | 图书评分,浮点型 |
| create_time | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 数据入库时间,自动生成 |
4.3 建表语句
标准 SQL 建表语句,后续在 Pipeline 中执行:
sql
CREATE TABLE IF NOT EXISTS book_info ( id INTEGER PRIMARY KEY AUTOINCREMENT, book_name TEXT NOT NULL, book_author TEXT, book_publisher TEXT, publish_date TEXT, book_price TEXT, book_score REAL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP );语句说明:
IF NOT EXISTS:避免重复创建表,爬虫多次启动不会报错。AUTOINCREMENT:主键自动递增,无需手动赋值。DEFAULT CURRENT_TIMESTAMP:自动记录数据入库时间,无需爬虫传递。
五、核心开发:Pipeline 实现数据写入 SQLite
5.1 Scrapy Pipeline 工作原理
Pipeline 是 Scrapy 的数据处理管道,核心工作流程:
- 爬虫解析数据 → 封装为 Item → 自动传递给 Pipeline。
- Pipeline 接收 Item 后,可执行数据清洗、数据验证、数据入库、数据去重等操作。
- 一个项目可配置多个 Pipeline,按优先级顺序执行。
- 必须在
settings.py中启用 Pipeline,否则数据不会进入管道处理。
本项目中,Pipeline 的核心职责:连接 SQLite 数据库 → 创建数据表 → 接收 Item → 插入数据到数据库。
5.2 编写 SQLite Pipeline 代码
打开pipelines.py文件,编写完整的数据入库逻辑,代码带详细注释:
python
运行
# Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html import sqlite3 from itemadapter import ItemAdapter class SqliteSpiderPipeline: """ SQLite数据入库管道 实现数据库连接、表创建、数据插入、数据库关闭全流程 """ def __init__(self): """ 初始化方法:创建数据库连接、创建游标、创建数据表 爬虫启动时自动执行一次 """ # 1. 连接SQLite数据库(文件名为data.db,不存在则自动创建) self.conn = sqlite3.connect('data.db') # 2. 创建数据库游标,用于执行SQL语句 self.cursor = self.conn.cursor() # 3. 执行建表语句 self.create_table() def create_table(self): """创建图书数据表,不存在则创建""" create_sql = ''' CREATE TABLE IF NOT EXISTS book_info ( id INTEGER PRIMARY KEY AUTOINCREMENT, book_name TEXT NOT NULL, book_author TEXT, book_publisher TEXT, publish_date TEXT, book_price TEXT, book_score REAL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ''' # 执行SQL语句 self.cursor.execute(create_sql) # 提交事务 self.conn.commit() def process_item(self, item, spider): """ 核心方法:处理每个Item,插入数据库 每传递一个Item,该方法执行一次 """ # 适配Item,获取字段数据 adapter = ItemAdapter(item) # 4. 插入数据SQL语句(?为SQLite占位符,防止SQL注入) insert_sql = ''' INSERT INTO book_info ( book_name, book_author, book_publisher, publish_date, book_price, book_score ) VALUES (?, ?, ?, ?, ?, ?); ''' # 5. 提取Item中的数据,按顺序组成元组 data = ( adapter.get('book_name'), adapter.get('book_author'), adapter.get('book_publisher'), adapter.get('publish_date'), adapter.get('book_price'), adapter.get('book_score') ) # 6. 执行插入语句 self.cursor.execute(insert_sql, data) # 7. 提交事务,保存数据到数据库 self.conn.commit() # 返回Item,便于后续管道处理(如果有多个管道) return item def close_spider(self, spider): """ 爬虫关闭时自动执行 关闭数据库游标和连接,释放资源 """ self.cursor.close() self.conn.close()5.3 代码核心原理剖析
__init__方法:爬虫启动时执行,仅执行一次,负责初始化数据库连接和创建表,避免重复操作。create_table方法:封装建表逻辑,提高代码可读性和可维护性。process_item方法:Pipeline 核心方法,必须实现,接收 Item 和爬虫对象,处理数据插入。- 占位符
?:SQLite 安全语法,替代字符串拼接,彻底防止 SQL 注入漏洞,生产环境必须使用。 close_spider方法:爬虫关闭时执行,关闭数据库连接,避免资源泄漏。- 事务提交
commit():SQLite 默认开启事务,执行增删改后必须提交,否则数据不会持久化。
5.4 启用 Pipeline 配置
打开settings.py文件,找到ITEM_PIPELINES配置项,取消注释并修改为:
python
运行
# Configure item pipelines # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { # 键:管道类路径,值:优先级(0-1000,数字越小优先级越高) 'sqlite_spider.pipelines.SqliteSpiderPipeline': 300, }配置说明:只有启用该配置,爬虫的 Item 才会进入自定义的 SQLite 管道,否则数据不会入库。
六、爬虫逻辑开发:数据解析与 Item 封装
6.1 爬虫开发原理
爬虫文件的核心职责:发送请求 → 获取响应 → 解析 HTML → 封装数据到 Item → 提交 Item 到 Pipeline。 Scrapy 基于 Twisted 异步框架,自动处理并发请求,无需手动管理线程,提升采集效率。
6.2 编写爬虫解析代码
打开spiders/book_spider.py文件,编写数据解析逻辑,本案例采集豆瓣图书榜单数据:
python
运行
import scrapy # 导入自定义的Item类 from sqlite_spider.items import SqliteSpiderItem class BookSpiderSpider(scrapy.Spider): # 爬虫名称,启动爬虫时使用 name = 'book_spider' # 允许爬取的域名,防止爬虫爬取其他站点 allowed_domains = ['book.douban.com'] # 起始URL,爬虫启动后首先请求该地址 start_urls = ['https://book.douban.com/top250'] def parse(self, response): """ 解析响应数据的核心方法 response:请求返回的响应对象,包含HTML、headers等信息 """ # 1. 使用XPath解析图书列表(匹配所有图书项) book_list = response.xpath('//tr[@class="item"]') # 遍历每一本图书 for book in book_list: # 2. 创建Item对象,封装数据 item = SqliteSpiderItem() # 解析图书名称 item['book_name'] = book.xpath('.//div[@class="pl2"]/a/@title').extract_first().strip() # 解析图书信息(作者、出版社、日期、价格) book_info = book.xpath('.//p[@class="pl"]/text()').extract_first().split(' / ') # 赋值作者 item['book_author'] = book_info[0] if len(book_info) > 0 else '' # 赋值出版社 item['book_publisher'] = book_info[1] if len(book_info) > 1 else '' # 赋值出版日期 item['publish_date'] = book_info[2] if len(book_info) > 2 else '' # 赋值价格 item['book_price'] = book_info[3] if len(book_info) > 3 else '' # 解析图书评分 item['book_score'] = book.xpath('.//span[@class="rating_nums"]/text()').extract_first() # 3. 提交Item到Pipeline,自动触发数据入库 yield item # 4. 解析下一页链接,实现翻页采集 next_page = response.xpath('//span[@class="next"]/a/@href').extract_first() if next_page: # 拼接完整URL next_url = response.urljoin(next_page) # 发送下一页请求,回调parse方法继续解析 yield scrapy.Request(next_url, callback=self.parse)6.3 爬虫代码核心解析
- 爬虫标识:
name是爬虫唯一名称,启动爬虫时必须使用该名称。 - XPath 解析:Scrapy 原生支持 XPath/CSS 选择器,是 HTML 解析的高效工具,
extract_first()获取单个数据,extract()获取列表数据。 yield item:将封装好的 Item 提交给框架,自动传递到 Pipeline 处理,这是 Scrapy 数据提交的标准方式。- 翻页逻辑:自动解析下一页链接,递归发送请求,实现全量数据采集。
- 容错处理:使用
if判断数据长度,避免数据缺失导致程序崩溃。
七、项目配置优化
7.1 基础配置优化
打开settings.py文件,修改以下配置,提升爬虫稳定性和合规性:
python
运行
# 1. 设置请求头,模拟浏览器访问,防止被反爬 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' # 2. 关闭 robots 协议检查(根据目标站点规则调整,学习环境使用) ROBOTSTXT_OBEY = False # 3. 设置并发请求数(默认16,轻量化项目调低避免给服务器造成压力) CONCURRENT_REQUESTS = 4 # 4. 设置请求延迟(单位:秒,防止请求过快被封IP) DOWNLOAD_DELAY = 1 # 5. 启用日志级别,减少冗余日志(DEBUG/INFO/WARNING/ERROR) LOG_LEVEL = 'INFO'7.2 配置作用原理
- USER_AGENT:伪装成浏览器,大部分站点会拦截无 UA 的爬虫请求。
- ROBOTSTXT_OBEY:是否遵守站点爬虫协议,学习环境可关闭,生产环境需遵守站点规则。
- CONCURRENT_REQUESTS:控制并发数,轻量化 SQLite 不支持高并发写入,调低数值保证数据入库稳定。
- DOWNLOAD_DELAY:请求间隔,降低目标服务器压力,避免被反爬机制封禁。
- LOG_LEVEL:日志级别,INFO 级别仅输出关键日志,便于调试。
八、启动爬虫与数据验证
8.1 启动 Scrapy 爬虫
进入项目根目录,执行以下命令启动爬虫:
bash
运行
# 启动爬虫,名称为爬虫文件中定义的name scrapy crawl book_spider启动成功后,终端输出 INFO 日志,显示爬虫开始请求、解析数据、插入数据库的过程。
8.2 数据校验方式
方式 1:使用 SQLiteStudio 可视化工具(推荐)
- 打开 SQLiteStudio 工具,点击「添加数据库」。
- 选择项目根目录下自动生成的
data.db文件,加载数据库。 - 展开
book_info表,查看数据,所有爬虫采集的数据已完整入库。
方式 2:使用 Python 代码查询数据
在项目根目录创建query_data.py文件,执行查询语句:
python
运行
import sqlite3 # 连接数据库 conn = sqlite3.connect('data.db') cursor = conn.cursor() # 查询所有数据 cursor.execute('SELECT * FROM book_info') data = cursor.fetchall() # 打印数据条数和前3条数据 print(f'总采集数据量:{len(data)} 条') print('前3条数据:') for item in data[:3]: print(item) # 关闭连接 cursor.close() conn.close()执行脚本,终端输出数据,证明入库成功。
九、项目核心知识点总结与扩展
9.1 核心流程总结
本项目完整实现了 Scrapy+SQLite 轻量化数据存储方案,核心流程:
- 环境安装 → 项目创建 → Item 数据建模。
- 数据库表设计 → Pipeline 数据入库开发。
- 爬虫解析开发 → 配置优化 → 启动爬虫 → 数据校验。
- 数据自动存储在
data.db文件中,可直接迁移、分析、导出。
9.2 关键技术点
- Scrapy 数据流转:请求→解析→Item→Pipeline→数据库,标准化流程。
- SQLite 安全写入:使用占位符防止 SQL 注入,事务提交保证数据持久化。
- 异步采集:Scrapy 异步框架高效采集,轻量化数据库无性能瓶颈。
- 模块化开发:Item、Pipeline、爬虫分离,符合软件工程规范。
9.3 扩展优化方向
- 数据去重:在 Pipeline 中添加去重逻辑,根据图书名称判断数据是否已存在,避免重复入库。
- 数据清洗:在
process_item中对价格、评分进行格式转换,统一数据类型。 - 多表存储:创建多个 Item 和 Pipeline,实现不同类型数据分别入库。
- 异常捕获:在数据库操作中添加
try-except,捕获数据库连接异常、数据插入异常,保证爬虫稳定运行。 - 批量插入:采集大量数据时,使用
executemany批量插入,提升入库效率。
9.4 扩展代码:数据去重 + 异常捕获
优化pipelines.py中的process_item方法,增加去重和异常处理:
python
运行
def process_item(self, item, spider): adapter = ItemAdapter(item) try: # 数据去重:根据图书名称判断是否已存在 check_sql = 'SELECT id FROM book_info WHERE book_name = ?' self.cursor.execute(check_sql, (adapter.get('book_name'),)) if self.cursor.fetchone(): self.logger.info(f'数据已存在:{adapter.get("book_name")},跳过插入') return item # 插入数据 insert_sql = ''' INSERT INTO book_info (book_name, book_author, book_publisher, publish_date, book_price, book_score) VALUES (?, ?, ?, ?, ?, ?); ''' data = ( adapter.get('book_name'), adapter.get('book_author'), adapter.get('book_publisher'), adapter.get('publish_date'), adapter.get('book_price'), adapter.get('book_score') ) self.cursor.execute(insert_sql, data) self.conn.commit() self.logger.info(f'数据插入成功:{adapter.get("book_name")}') except Exception as e: # 回滚事务,保证数据一致性 self.conn.rollback() self.logger.error(f'数据插入失败:{str(e)},数据:{adapter.get("book_name")}') return item该优化解决了重复数据入库、数据库异常导致程序崩溃的问题,生产环境可直接使用。
十、项目部署与注意事项
10.1 项目部署
本项目为轻量化爬虫,部署极其简单:
- 将整个项目文件夹拷贝到目标服务器(Windows/Linux/macOS 均可)。
- 服务器安装 Python3.8 + 和 Scrapy 依赖。
- 执行启动命令,自动生成数据库并采集数据。
10.2 注意事项
- SQLite 并发限制:SQLite 不支持高并发写入,Scrapy 并发数建议设置为 1-4,避免数据库锁表。
- 数据备份:定期拷贝
data.db文件,实现数据备份,防止文件丢失。 - 反爬合规:爬虫需遵守目标站点规则,仅采集公开数据,禁止用于商业用途和非法采集。
- 资源释放:必须实现
close_spider方法,关闭数据库连接,避免文件占用。 - 日志监控:通过日志查看爬虫运行状态,及时处理异常。
