Scrapy是Python生态中功能完善的Web爬虫框架,它基于异步IO实现,能够高效处理大规模的网页采集任务,同时提供了丰富的中间件和扩展接口,方便开发者根据需求定制功能。本文将从框架核心组件、项目搭建、数据存储实践三个维度展开讲解。

Scrapy框架核心组件解析
Scrapy的架构由多个核心组件协同工作,理解这些组件的作用是实现高级功能的基础:
- Spider:爬虫逻辑的核心,负责定义采集的起始URL、解析响应数据、提取目标字段和生成新的请求。
- Engine:框架的调度中枢,负责控制所有组件之间的数据流,触发事务处理。
- Scheduler:请求调度器,接收Engine发来的请求并排队,在合适的时候返回给Engine。
- Downloader:下载器,负责发送请求获取网页响应,然后将响应返回给Engine。
- Item Pipeline:数据管道,负责处理Spider提取到的数据,常见的操作包括数据清洗、验证、存储。
- Middleware:包括Spider中间件和Downloader中间件,用于在请求和响应的处理过程中插入自定义逻辑,比如添加请求头、处理反爬、重试失败请求等。
Scrapy项目搭建与基础爬虫实现
首先需要通过pip安装Scrapy框架:
pip install scrapy
安装完成后,使用命令行创建Scrapy项目:
scrapy startproject book_spider cd book_spider scrapy genspider book_douban douban.com
上述命令会创建一个名为book_spider的项目,并在spiders目录下生成book_douban爬虫文件。接下来编写基础爬虫逻辑,以采集豆瓣图书的基本信息为例:
import scrapy
class BookDoubanSpider(scrapy.Spider):
name = "book_douban" # 爬虫名称,运行爬虫时需要使用
allowed_domains = ["douban.com"] # 允许采集的域名
start_urls = ["https://www.douban.com/tag/小说/book"] # 起始URL
def parse(self, response):
# 提取所有图书条目
book_list = response.xpath('//div[@class="mod book-list"]/dl/dd')
for book in book_list:
item = {
"title": book.xpath('./a/text()').get(),
"author": book.xpath('./p[1]/text()').get(),
"score": book.xpath('./p[2]/span[@class="rating_nums"]/text()').get(),
"link": book.xpath('./a/@href').get()
}
yield item
# 提取下一页链接,生成新的请求
next_page = response.xpath('//span[@class="next"]/a/@href').get()
if next_page:
yield scrapy.Request(url=response.urljoin(next_page), callback=self.parse)
数据存储实践方案
Scrapy提供了多种数据存储的方式,开发者可以根据数据规模和后续使用场景选择合适的方案,以下是三种常见的存储实践。
方案一:存储到JSON文件
Scrapy内置了Feed Exports功能,可以直接将采集到的数据导出为JSON、CSV等格式的文件,无需额外编写存储逻辑。运行爬虫时指定输出格式和路径即可:
scrapy crawl book_douban -o book_data.json
如果需要自定义JSON的输出格式,比如设置编码、缩进,可以在项目的settings.py中配置:
# settings.py中添加配置 FEED_EXPORT_ENCODING = "utf-8" # 设置输出编码 FEED_FORMAT = "json" # 默认输出格式 FEED_URI = "book_data.json" # 默认输出路径
方案二:存储到MySQL关系型数据库
当需要对采集到的数据进行结构化查询和管理时,MySQL是常用的选择。首先需要安装pymysql驱动:
pip install pymysql
然后在settings.py中配置MySQL连接信息:
# settings.py中添加配置 MYSQL_HOST = "127.0.0.1" MYSQL_PORT = 3306 MYSQL_USER = "root" MYSQL_PASSWORD = "123456" MYSQL_DATABASE = "spider_data"
接下来编写Item Pipeline实现数据入库,首先在pipelines.py中定义存储管道:
import pymysql
from itemadapter import ItemAdapter
class MysqlPipeline:
def __init__(self, mysql_host, mysql_port, mysql_user, mysql_password, mysql_database):
self.host = mysql_host
self.port = mysql_port
self.user = mysql_user
self.password = mysql_password
self.database = mysql_database
self.conn = None
self.cursor = None
@classmethod
def from_crawler(cls, crawler):
# 从settings中获取配置参数
return cls(
mysql_host=crawler.settings.get("MYSQL_HOST"),
mysql_port=crawler.settings.get("MYSQL_PORT"),
mysql_user=crawler.settings.get("MYSQL_USER"),
mysql_password=crawler.settings.get("MYSQL_PASSWORD"),
mysql_database=crawler.settings.get("MYSQL_DATABASE")
)
def open_spider(self, spider):
# 爬虫启动时建立数据库连接
self.conn = pymysql.connect(
host=self.host,
port=self.port,
user=self.user,
password=self.password,
database=self.database,
charset="utf8mb4"
)
self.cursor = self.conn.cursor()
# 创建数据表,如果不存在则创建
create_table_sql = """
CREATE TABLE IF NOT EXISTS douban_book (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
author VARCHAR(255),
score VARCHAR(10),
link VARCHAR(500),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
"""
self.cursor.execute(create_table_sql)
self.conn.commit()
def process_item(self, item, spider):
adapter = ItemAdapter(item)
# 插入数据
insert_sql = """
INSERT INTO douban_book (title, author, score, link)
VALUES (%s, %s, %s, %s)
"""
self.cursor.execute(insert_sql, (
adapter.get("title"),
adapter.get("author"),
adapter.get("score"),
adapter.get("link")
))
self.conn.commit()
return item
def close_spider(self, spider):
# 爬虫关闭时释放资源
if self.cursor:
self.cursor.close()
if self.conn:
self.conn.close()
最后在settings.py中启用该管道:
ITEM_PIPELINES = {
"book_spider.pipelines.MysqlPipeline": 300, # 数值越小优先级越高
}
方案三:存储到MongoDB非关系型数据库
如果采集的数据结构不固定,或者需要更高的写入性能,MongoDB是更合适的选择。首先安装pymongo驱动:
pip install pymongo
在settings.py中配置MongoDB连接信息:
# settings.py中添加配置 MONGO_URI = "127.0.0.1:27017" MONGO_DATABASE = "spider_data"
编写MongoDB存储管道:
import pymongo
from itemadapter import ItemAdapter
class MongoPipeline:
def __init__(self, mongo_uri, mongo_database):
self.mongo_uri = mongo_uri
self.mongo_database = mongo_database
self.client = None
self.db = None
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get("MONGO_URI"),
mongo_database=crawler.settings.get("MONGO_DATABASE")
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_database]
def process_item(self, item, spider):
adapter = ItemAdapter(item)
# 插入数据到douban_book集合
self.db["douban_book"].insert_one(dict(adapter))
return item
def close_spider(self, spider):
if self.client:
self.client.close()
同样在settings.py中启用该管道即可。
高级功能扩展
请求去重与增量爬取
Scrapy默认使用RFPDupeFilter进行请求去重,基于请求的URL进行判断。如果需要实现增量爬取,避免重复采集已经获取过的数据,可以自定义去重逻辑,比如基于数据的唯一标识(如图书的ID)进行去重。可以在Spider中维护一个已采集ID的集合,或者在Pipeline中判断数据是否已经存在再决定是否入库。
反爬处理中间件
很多网站会有反爬机制,比如检测请求头、限制访问频率、返回验证码等。可以通过自定义Downloader中间件来处理这些问题:
class CustomDownloaderMiddleware:
def process_request(self, request, spider):
# 添加随机User-Agent
user_agent_list = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15"
]
request.headers["User-Agent"] = random.choice(user_agent_list)
# 添加自定义请求头
request.headers["Referer"] = "https://www.douban.com"
return None
def process_response(self, request, response, spider):
# 如果响应状态码是403,说明被反爬,重新发送请求
if response.status == 403:
return request.replace(dont_filter=True)
return response
将该中间件配置到settings.py的DOWNLOADER_MIDDLEWARES中即可生效。
常见问题与优化建议
在实际使用Scrapy时,可能会遇到一些问题,以下是常见的优化方向:
- 调整并发请求数量:在settings.py中设置CONCURRENT_REQUESTS参数,默认是16,可以根据目标网站的承受能力和自身网络情况调整,但不要设置过高避免被封禁。
- 设置请求延迟:通过DOWNLOAD_DELAY参数设置每个请求之间的延迟时间,降低被反爬的概率。
- 启用自动限速:设置AUTOTHROTTLE_ENABLED为True,Scrapy会根据目标网站的响应延迟自动调整请求频率。
- 处理请求失败重试:默认的RetryMiddleware会自动重试失败的请求,可以通过RETRY_TIMES参数调整重试次数。
通过上述内容的实践,开发者可以掌握Scrapy框架的核心用法,并且能够根据实际需求选择合适的存储方案,实现稳定高效的Web爬虫数据采集与存储。
ScrapyPython_Web_crawlerdata_storagespider_middleware修改时间:2026-07-16 10:21:24