Python 爬虫项目 Scrapy 爬虫数据直连 MySQL 入库实战

发布时间:2026/6/8 0:00:45

Python 爬虫项目 Scrapy 爬虫数据直连 MySQL 入库实战 前言数据持久化是爬虫工程落地的关键环节Scrapy 框架本身仅负责请求调度、页面抓取与数据解析并未内置数据库写入能力因此需要借助管道组件完成解析数据向 MySQL 数据库的同步存储。相较于本地文件存储MySQL 关系型数据库具备数据检索、多维度查询、事务管理、权限控制与分布式读写等优势是中大型爬虫项目、长期数据采集场景下的主流存储方案。本文围绕 Scrapy 对接 MySQL 数据库展开全流程实战涵盖环境依赖安装、数据库表结构设计、项目配置、管道编写、异步入库、异常处理、批量优化等内容区分同步写入与异步写入两种主流实现方案同时梳理生产环境下的性能调优、事务控制与故障排查方案所有代码均可直接部署运行适配单机爬虫与多爬虫并行采集场景。本文涉及的核心依赖、工具及官方文档链接如下可直接跳转查阅对应资源Scrapy 官方文档框架管道、信号、中间件等核心模块说明MySQL 官方文档数据库语法、引擎、索引及运维规范pymysql 官方文档Python 操作 MySQL 主流库接口说明Twisted 异步框架文档Scrapy 异步 IO 底层依赖异步数据库读写核心支撑mysqlclient 官方说明高性能 MySQL 连接客户端本文基于标准 Scrapy 项目结构开发从基础连接到生产级优化逐步讲解兼顾入门学习与工程化落地需求。一、环境准备与依赖安装1.1 基础环境要求运行本文案例需满足基础运行环境Python 3.7 及以上版本、Scrapy 2.5 及以上版本、MySQL 5.7 或 MySQL 8.0 数据库服务数据库服务可部署在本地服务器、远程云服务器或虚拟机中需保证爬虫项目所在主机可正常连通数据库端口。1.2 数据库操作依赖库Python 生态中常用的 MySQL 操作库包含pymysql、mysqlclient两类二者语法基本兼容特性存在一定差异下表对两款库进行对比说明表格依赖库名称运行特性安装难度性能表现适用场景pymysql纯 Python 实现跨平台兼容性强无需本地编译低直接 pip 安装中等开发测试、Windows 系统、轻量化爬虫项目mysqlclientC 语言底层封装依赖本地 MySQL 开发组件高Linux 需预装依赖包高读写速度更快生产环境、Linux 服务器、大数据量爬虫1.2.1 安装 pymysql通用方案Windows、macOS、Linux 系统均可直接执行以下命令安装无额外环境依赖适合绝大多数开发场景bash运行pip install pymysql1.2.2 安装 mysqlclient生产高性能方案Windows 系统可直接使用 pip 安装Linux 系统需先安装系统级依赖再安装 Python 库命令如下bash运行# CentOS / RedHat 系统预装依赖 yum install python3-devel mysql-devel -y # Ubuntu / Debian 系统预装依赖 apt-get install python3-dev libmysqlclient-dev -y # 安装 mysqlclient pip install mysqlclient1.3 数据库服务检查安装完成后先确认 MySQL 服务正常运行本地数据库可通过客户端工具、命令行登录测试连通性。本地登录命令参考bash运行mysql -u 用户名 -p输入密码后进入数据库交互界面代表数据库服务运行正常可进行后续建库、建表操作。二、MySQL 数据库与数据表设计数据入库前需提前规划数据库、数据表结构字段设计需与 Scrapy 项目中 Item 实体类一一对应同时合理设置字段类型、长度、主键、索引保障数据存储规范与查询效率。2.1 创建专属数据库建议为爬虫项目单独创建数据库区分业务数据与其他数据避免表名冲突。执行以下 SQL 语句创建数据库并指定字符集为utf8mb4该字符集支持全量中文、表情符号及特殊字符是爬虫项目的标准字符集配置sql-- 创建爬虫专用数据库 CREATE DATABASE IF NOT EXISTS scrapy_data DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 切换至目标数据库 USE scrapy_data;2.2 数据表结构设计本文以通用资讯类爬虫为例设计数据表存储标题、链接、发布时间、内容、来源站点等字段设置自增主键作为唯一标识对网址、标题等高频查询字段建立索引。数据表创建语句如下sql-- 创建资讯数据表 CREATE TABLE IF NOT EXISTS news_info ( id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 自增主键, title VARCHAR(255) NOT NULL COMMENT 资讯标题, url VARCHAR(512) NOT NULL COMMENT 原文链接, publish_time VARCHAR(64) DEFAULT COMMENT 发布时间, content TEXT COMMENT 正文内容, source VARCHAR(128) DEFAULT COMMENT 来源站点, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 数据入库时间, PRIMARY KEY (id), UNIQUE INDEX idx_url (url) COMMENT 链接唯一索引防止重复入库, INDEX idx_title (title) COMMENT 标题查询索引 ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COMMENT 爬虫采集资讯数据表;2.2.1 表结构核心说明存储引擎选用 InnoDB支持事务、行级锁、数据回滚数据安全性更高适配爬虫异常场景下的数据容错唯一索引 idx_url基于文章链接建立唯一索引从数据库层面拦截重复数据弥补爬虫去重逻辑的漏洞字段类型短文本使用 VARCHAR长文本正文使用 TEXT 类型兼顾存储效率与内容长度适配入库时间字段create_time设置默认值为当前时间无需爬虫主动传入由数据库自动生成。2.3 数据库账号权限配置为保障数据库安全不建议使用 root 超级账号进行爬虫数据写入可单独创建专用账号并分配权限SQL 语句参考sql-- 创建爬虫专用账号允许本地及远程访问 CREATE USER scrapy_user% IDENTIFIED BY Scrapy123456; -- 为账号分配目标数据库全部权限 GRANT ALL PRIVILEGES ON scrapy_data.* TO scrapy_user%; -- 刷新权限使其生效 FLUSH PRIVILEGES;账号、密码、IP 访问范围可根据实际部署环境自行修改。三、Scrapy 项目基础配置与 Item 定义基于已有 Scrapy 项目开展开发若暂无项目可通过命令快速创建新项目与爬虫文件本节完成 Item 实体定义、基础参数配置为数据入库做准备。3.1 项目与爬虫创建执行终端命令创建项目及测试爬虫bash运行# 创建 Scrapy 项目 scrapy startproject mysql_demo # 进入项目目录 cd mysql_demo # 创建爬虫文件 scrapy genspider news_spider 测试域名3.2 定义 Item 数据实体Scrapy 中 Item 用于结构化存储爬虫解析出的字段相当于数据实体类需与 MySQL 数据表字段一一对应。打开项目目录下items.py文件编写 Item 代码python运行import scrapy class NewsInfoItem(scrapy.Item): # 对应数据表 title 字段资讯标题 title scrapy.Field() # 对应数据表 url 字段原文链接 url scrapy.Field() # 对应数据表 publish_time 字段发布时间 publish_time scrapy.Field() # 对应数据表 content 字段正文内容 content scrapy.Field() # 对应数据表 source 字段来源站点 source scrapy.Field()3.2.1 代码原理scrapy.Field()是 Scrapy 内置字段类型仅用于标记数据字段名称不限制数据类型解析得到的字符串、数字等数据均可存入对应字段。爬虫解析完成后会将数据封装为 Item 对象再交由管道Pipeline进行后续处理。3.3 全局配置文件基础设置打开settings.py文件关闭无用配置、开启日志同时预留数据库连接配置项。首先关闭 robots 协议校验、Cookie 跟踪根据业务需求调整配置日志级别python运行# 关闭 robots.txt 协议检测 ROBOTSTXT_OBEY False # 关闭 Cookie 启用无 Cookie 采集需求时建议关闭 COOKIES_ENABLED False # 设置日志级别为 DEBUG方便调试 LOG_LEVEL DEBUG # 数据库全局配置项 # 数据库地址 MYSQL_HOST 127.0.0.1 # 数据库端口MySQL 默认端口 3306 MYSQL_PORT 3306 # 数据库名称 MYSQL_DB scrapy_data # 数据库用户名 MYSQL_USER scrapy_user # 数据库密码 MYSQL_PASSWORD Scrapy123456 # 数据库字符集 MYSQL_CHARSET utf8mb4将数据库连接信息统一写入settings.py便于后期统一修改、环境切换符合工程化代码规范。四、同步模式 MySQL 数据入库基础方案同步入库是入门阶段最常用的实现方式基于pymysql建立数据库长连接通过 Scrapy 管道逐行执行 SQL 插入语句完成数据存储。该方案代码简单、逻辑直观适合数据量小、采集速度慢的轻量化爬虫项目。4.1 编写 MySQL 同步管道管道文件为项目目录下的pipelines.py新建 MySQL 存储管道类实现数据库连接初始化、数据插入、连接销毁全逻辑完整代码如下python运行import pymysql from pymysql import Error class MysqlSyncPipeline: def __init__(self, host, port, user, password, db, charset): # 初始化数据库连接参数 self.host host self.port port self.user user self.password password self.db db self.charset charset # 数据库连接对象 self.conn None # 游标对象用于执行 SQL self.cursor None classmethod def from_crawler(cls, crawler): 从全局配置读取数据库参数Scrapy 管道标准入口方法 return cls( hostcrawler.settings.get(MYSQL_HOST), portcrawler.settings.get(MYSQL_PORT), usercrawler.settings.get(MYSQL_USER), passwordcrawler.settings.get(MYSQL_PASSWORD), dbcrawler.settings.get(MYSQL_DB), charsetcrawler.settings.get(MYSQL_CHARSET) ) def open_spider(self, spider): 爬虫启动时执行创建数据库连接与游标 try: # 建立数据库连接 self.conn pymysql.connect( hostself.host, portself.port, userself.user, passwordself.password, databaseself.db, charsetself.charset ) # 创建游标 self.cursor self.conn.cursor() spider.logger.info(数据库连接创建成功) except Error as e: spider.logger.error(f数据库连接失败{str(e)}) def process_item(self, item, spider): 核心方法每一条 Item 数据都会进入该方法执行入库逻辑 # 构造插入 SQL 语句%s 为参数占位符防止 SQL 注入 insert_sql INSERT INTO news_info(title, url, publish_time, content, source) VALUES (%s, %s, %s, %s, %s) # 组装参数元组 params ( item.get(title, ), item.get(url, ), item.get(publish_time, ), item.get(content, ), item.get(source, ) ) try: # 执行 SQL 语句 self.cursor.execute(insert_sql, params) # 手动提交事务InnoDB 引擎必须执行 commit 才会真正写入数据 self.conn.commit() spider.logger.info(f数据入库成功{item.get(url)}) except Error as e: # 出现异常则回滚事务避免脏数据 self.conn.rollback() spider.logger.error(f数据入库失败链接{item.get(url)}错误信息{str(e)}) # 必须返回 item保证后续管道可继续处理数据 return item def close_spider(self, spider): 爬虫关闭时执行销毁游标与数据库连接释放资源 if self.cursor: self.cursor.close() if self.conn: self.conn.close() spider.logger.info(数据库连接已关闭)4.2 管道核心逻辑原理from_crawler 方法Scrapy 管道专属类方法作用是读取settings.py中的全局配置将数据库参数传入管道构造函数实现配置与代码解耦open_spider 方法生命周期方法仅在爬虫启动执行一次在此处创建数据库长连接避免每条数据都新建连接减少连接开销process_item 方法管道核心回调解析后的每一条 Item 都会进入该方法。使用参数化 SQL拼接语句而非字符串拼接从代码层面抵御 SQL 注入攻击事务管理InnoDB 引擎默认开启事务执行execute后数据仅存于事务缓冲区必须调用commit()才会落地到数据库执行异常时调用rollback()回滚事务防止部分字段写入造成脏数据close_spider 方法爬虫停止时关闭游标与数据库连接释放服务器资源避免连接泄露。4.3 启用自定义管道编写完成管道后需要在settings.py中注册管道Scrapy 才会加载并执行入库逻辑。找到ITEM_PIPELINES配置项添加自定义管道配置如下python运行# 启用数据管道数字代表管道执行优先级数值越小越先执行 ITEM_PIPELINES { mysql_demo.pipelines.MysqlSyncPipeline: 300, }优先级数值可自定义单个管道场景下无严格限制多管道协同场景需根据业务流程调整顺序。4.4 编写爬虫解析逻辑打开spiders/news_spider.py编写页面请求与数据解析逻辑模拟真实爬虫采集流程将解析数据封装为 Item 对象python运行import scrapy from mysql_demo.items import NewsInfoItem class NewsSpider(scrapy.Spider): name news_spider allowed_domains [example.com] start_urls [https://example.com] def parse(self, response): # 模拟页面数据解析实际项目替换为 XPath / CSS 选择器 item NewsInfoItem() item[title] 测试资讯标题 item[url] response.url item[publish_time] 2026-06-07 10:00:00 item[content] 这是爬虫采集的正文测试内容 item[source] 示例站点 # 提交 Item 至管道执行入库操作 yield item4.5 运行爬虫验证入库结果终端执行爬虫启动命令bash运行scrapy crawl news_spider观察日志输出若打印数据库连接创建成功、数据入库成功等日志代表流程执行正常。登录 MySQL 数据库执行查询语句验证数据sqlSELECT * FROM news_info;若查询到对应测试数据说明同步入库方案搭建完成。4.6 同步方案优缺点分析表格优势劣势代码逻辑简单入门门槛低易于维护和调试单条数据单次提交事务IO 开销大高并发下性能较差异常捕获直观事务回滚精准数据安全性高爬虫采集速度快时数据库写入成为性能瓶颈兼容性强全平台均可稳定运行不适合大数据量、高吞吐的生产爬虫场景五、异步模式 MySQL 数据入库进阶方案Scrapy 基于 Twisted 异步 IO 框架开发同步数据库读写会阻塞异步事件循环大幅降低爬虫整体性能。针对大数据量采集场景业界主流方案为异步 MySQL 入库借助 Twisted 内置的异步数据库组件实现非阻塞写入充分发挥 Scrapy 异步特性。5.1 异步依赖与组件说明Twisted 框架提供adbapi模块专门用于异步数据库操作无需额外安装第三方库Scrapy 环境默认集成。adbapi会维护数据库连接池所有 SQL 操作均在线程池中异步执行不会阻塞爬虫的请求调度与页面解析流程。5.2 编写 MySQL 异步管道修改pipelines.py新增异步数据库管道完整代码如下python运行from twisted.enterprise import adbapi import pymysql.cursors class MysqlAsyncPipeline: def __init__(self, db_pool): # 接收数据库连接池对象 self.db_pool db_pool classmethod def from_crawler(cls, crawler): 初始化数据库连接池 # 读取全局数据库配置 db_params dict( hostcrawler.settings.get(MYSQL_HOST), portcrawler.settings.get(MYSQL_PORT), usercrawler.settings.get(MYSQL_USER), passwordcrawler.settings.get(MYSQL_PASSWORD), dbcrawler.settings.get(MYSQL_DB), charsetcrawler.settings.get(MYSQL_CHARSET), cursorclasspymysql.cursors.DictCursor ) # 创建 Twisted 异步数据库连接池 db_pool adbapi.ConnectionPool(pymysql, **db_params) return cls(db_pool) def process_item(self, item, spider): 异步执行数据入库 # runInteraction在线程池异步执行同步函数 query self.db_pool.runInteraction(self.do_insert, item, spider) # 绑定异常回调函数 query.addErrback(self.handle_error, item, spider) return item def do_insert(self, cursor, item, spider): 实际执行 SQL 插入的同步函数由线程池调用 insert_sql INSERT INTO news_info(title, url, publish_time, content, source) VALUES (%s, %s, %s, %s, %s) params ( item.get(title, ), item.get(url, ), item.get(publish_time, ), item.get(content, ), item.get(source, ) ) cursor.execute(insert_sql, params) spider.logger.info(f异步入库成功{item.get(url)}) def handle_error(self, failure, item, spider): 异步操作异常回调捕获数据库写入错误 spider.logger.error(f异步入库异常{failure.value}异常数据{item})5.3 异步管道核心原理连接池初始化adbapi.ConnectionPool创建数据库连接池预先创建多个数据库连接复用连接资源避免频繁创建销毁连接带来的性能损耗runInteraction 方法Twisted 异步核心方法将数据库操作放入独立线程池执行和 Scrapy 主线程解耦主线程继续处理请求与解析不会被数据库 IO 阻塞do_insert 函数真正执行 SQL 的同步函数接收游标对象与 Item 数据逻辑和同步方案基本一致异常回调 addErrback异步代码无法通过常规 try-except 捕获异常需单独绑定异常回调函数记录错误日志便于排查问题。5.4 启用异步管道修改settings.py中的ITEM_PIPELINES配置切换为异步管道python运行ITEM_PIPELINES { mysql_demo.pipelines.MysqlAsyncPipeline: 300, }保持爬虫代码不变重新启动爬虫即可运行异步入库逻辑。5.5 异步方案优缺点分析表格优势劣势非阻塞 IO贴合 Scrapy 异步架构整体采集效率大幅提升异步异常排查难度高于同步代码连接池复用连接数据库资源利用率更高事务管控相对复杂不适合强事务依赖的业务支持高并发写入适配大数据量爬虫项目入门学习成本略高六、批量插入优化高性能生产方案单条插入无论同步还是异步在十万级、百万级数据量下仍存在频繁 SQL 执行的性能问题。MySQL 支持INSERT INTO ... VALUES (...), (...), (...)语法实现批量插入将多条数据合并为一条 SQL 提交大幅减少 SQL 执行次数与网络交互次数是生产环境最优的入库方案。6.1 批量插入管道实现基于异步连接池结合批量缓存逻辑编写批量入库管道设置缓存阈值累计指定条数数据后统一执行批量插入代码如下python运行from twisted.enterprise import adbapi import pymysql.cursors class MysqlBatchPipeline: def __init__(self, db_pool, batch_size): self.db_pool db_pool # 批量插入阈值累计数据达到该数量则执行入库 self.batch_size batch_size # 数据缓存列表 self.data_list [] classmethod def from_crawler(cls, crawler): db_params dict( hostcrawler.settings.get(MYSQL_HOST), portcrawler.settings.get(MYSQL_PORT), usercrawler.settings.get(MYSQL_USER), passwordcrawler.settings.get(MYSQL_PASSWORD), dbcrawler.settings.get(MYSQL_DB), charsetcrawler.settings.get(MYSQL_CHARSET), cursorclasspymysql.cursors.DictCursor ) db_pool adbapi.ConnectionPool(pymysql, **db_params) # 从配置读取批量阈值默认 50 条 batch_size crawler.settings.get(BATCH_SIZE, 50) return cls(db_pool, batch_size) def process_item(self, item, spider): # 将单条数据加入缓存列表 data ( item.get(title, ), item.get(url, ), item.get(publish_time, ), item.get(content, ), item.get(source, ) ) self.data_list.append(data) # 判断是否达到批量阈值 if len(self.data_list) self.batch_size: self.batch_insert(spider) # 清空缓存 self.data_list [] return item def batch_insert(self, spider): 执行批量插入 query self.db_pool.runInteraction(self.do_batch_insert) query.addErrback(self.handle_batch_error, spider) def do_batch_insert(self, cursor): # 构造批量插入 SQL insert_sql INSERT INTO news_info(title, url, publish_time, content, source) VALUES (%s, %s, %s, %s, %s) # executemany 支持批量参数传入 cursor.executemany(insert_sql, self.data_list) def handle_batch_error(self, failure, spider): spider.logger.error(f批量入库异常{failure.value}) def close_spider(self, spider): 爬虫关闭时将缓存中剩余不足阈值的数据执行入库 if len(self.data_list) 0: self.batch_insert(spider) spider.logger.info(f收尾批量入库剩余数据{len(self.data_list)} 条)6.2 配置批量参数并启用管道在settings.py中新增批量阈值配置并注册管道python运行# 批量插入数据阈值 BATCH_SIZE 50 ITEM_PIPELINES { mysql_demo.pipelines.MysqlBatchPipeline: 300, }6.3 批量插入核心原理数据缓存使用列表临时缓存解析后的 Item 数据不立即执行 SQL阈值触发缓存数据达到设定阈值时调用executemany方法批量执行插入该方法是 pymysql 提供的批量执行接口底层拼接多条记录完成单次 SQL 请求收尾处理爬虫停止时缓存列表中可能存在不足阈值的剩余数据通过close_spider方法兜底入库避免数据丢失性能提升50 条数据合并为一次网络请求、一次事务提交相比单条插入IO 开销降低数十倍大数据量场景下提升效果极其明显。七、常见异常、问题排查与生产最佳实践7.1 高频异常及解决方案数据库连接超时、连接拒绝原因数据库地址、端口、账号密码配置错误远程数据库未开放防火墙端口MySQL 服务未启动。 解决核对settings.py数据库参数Linux 服务器放行 3306 端口重启 MySQL 服务。字符集乱码原因数据库、数据表、连接字符集不统一。 解决统一设置为utf8mb4建库建表语句、代码连接参数保持一致。主键 / 唯一索引冲突重复数据原因爬虫重复抓取同一链接触发唯一索引约束。 解决数据表添加ON DUPLICATE KEY UPDATE语法冲突时更新数据而非报错修改 SQL 语句即可实现。连接数过多连接耗尽原因未关闭数据库连接、连接池参数不合理。 解决同步方案确保close_spider正常执行异步连接池根据服务器配置调整最大连接数。7.2 生产环境最佳实践参数化 SQL 强制使用禁止字符串拼接 SQL彻底防范 SQL 注入风险优先使用批量异步入库十万级以上数据必须采用批量 异步方案平衡性能与稳定性合理设置批量阈值常规场景 30~100 条为最优区间阈值过大易造成单条 SQL 体积超标数据库分层部署采集库、查询库分离主库负责写入从库负责业务查询读写分离提升吞吐日志分级记录生产环境关闭 DEBUG 日志仅保留错误日志减少磁盘占用定时巡检数据结合定时脚本核对采集总量与数据库存储总量及时发现数据丢失问题。

相关新闻