Scrapy 核心组件 Scrapy 核心组件详解与实践 Scrapy 架构概览 首先,我们使用 Mermaid 图表来展示 Scrapy 的整体架构: 图表解释: Scrapy Engine: 引擎是 Scrapy 的核心,负责控制数据流在所有组件之间的流动。 Scheduler: 调度器接收引擎发来的请求,并将其放入队列中,以便稍后由下载器下载。 Downloader: 下载器负责下载网页,并将响应传递给 Spider。 Spider: Spider 定义了如何抓取特定的网站,并从页面中提取结构化数据。 Item Pipeline: Item Pipeline 负责处理 Spider 提取的 Items,例如清洗、验证和存储数据。
首先,我们使用 Mermaid 图表来展示 Scrapy 的整体架构:
图表解释:
Scrapy Engine: 引擎是 Scrapy 的核心,负责控制数据流在所有组件之间的流动。
Scheduler: 调度器接收引擎发来的请求,并将其放入队列中,以便稍后由下载器下载。
Downloader: 下载器负责下载网页,并将响应传递给 Spider。
Spider: Spider 定义了如何抓取特定的网站,并从页面中提取结构化数据。
Item Pipeline: Item Pipeline 负责处理 Spider 提取的 Items,例如清洗、验证和存储数据。
Spider Middleware: Spider 中间件可以修改进入 Spider 的请求和离开 Spider 的响应。
Downloader Middleware: 下载器中间件可以修改发送给下载器的请求和下载器接收到的响应。
现在,让我们深入了解每个核心组件,并提供代码示例。
引擎是 Scrapy 的核心,它负责控制所有组件之间的数据流。 你无需直接编写代码来操作引擎,因为它在 Scrapy 框架内部运行。 引擎负责启动爬虫、调度请求、处理响应和 Item,以及在组件之间传递信号。
调度器负责接收引擎发送的请求,并将它们放入队列中。 它还负责去重,确保同一个 URL 不会被多次抓取。 Scrapy 默认使用 scrapy.dupefilters.RFPDupeFilter 进行去重,它基于请求指纹(request fingerprint)来判断请求是否重复。
代码示例 (自定义调度器 - 仅供演示,不推荐直接替换默认调度器):
# my_scheduler.py from scrapy.dupefilters import RFPDupeFilter from scrapy.utils.request import request_fingerprint class CustomScheduler: def __init__(self, dupefilter): self.dupefilter = dupefilter self.queue = [] @classmethod def from_crawler(cls, crawler): return cls(RFPDupeFilter()) def enqueue_request(self, request): if not self.dupefilter.request_seen(request): self.queue.append(request) return True return False def next_request(self): if self.queue: return self.queue.pop(0) def has_pending_requests(self): return bool(self.queue) def close(self, reason): self.dupefilter.close(reason) def __len__(self): return len(self.queue)
配置自定义调度器 (settings.py):
# settings.py SCHEDULER = 'my_project.my_scheduler.CustomScheduler'
解释:
CustomScheduler 类实现了自定义调度器。
enqueue_request 方法将请求添加到队列中,并使用 RFPDupeFilter 进行去重。
next_request 方法从队列中获取下一个请求。
has_pending_requests 方法检查队列是否为空。
from_crawler 是一个类方法,用于从 Crawler 对象创建调度器实例。
注意: 通常情况下,不需要自定义调度器。 Scrapy 默认的调度器已经足够强大和灵活。
下载器负责下载网页。 Scrapy 默认使用 Twisted 异步网络库来处理下载。 下载器中间件可以用来修改请求头、设置代理、处理重定向等。
代码示例 (自定义下载器中间件 - 设置 User-Agent):
# my_middleware.py class CustomUserAgentMiddleware: def process_request(self, request, spider): request.headers['User-Agent'] = 'My Custom User Agent' def process_response(self, request, response, spider): return response def process_exception(self, request, exception, spider): return None
配置下载器中间件 (settings.py):
# settings.py DOWNLOADER_MIDDLEWARES = { 'my_project.my_middleware.CustomUserAgentMiddleware': 543, }
解释:
CustomUserAgentMiddleware 类实现了自定义下载器中间件。
process_request 方法在请求发送给下载器之前被调用,可以修改请求头。
process_response 方法在下载器收到响应之后被调用,可以修改响应。
process_exception 方法在下载过程中发生异常时被调用,可以处理异常。
DOWNLOADER_MIDDLEWARES 设置指定了要启用的下载器中间件及其优先级。
Spider 定义了如何抓取特定的网站,并从页面中提取结构化数据。 你需要编写 Spider 类来指定起始 URL、解析网页和提取数据。
代码示例 (一个简单的 Spider):
# my_spider.py import scrapy class MySpider(scrapy.Spider): name = 'my_spider' start_urls = ['http://quotes.toscrape.com/'] def parse(self, response): for quote in response.css('.quote'): yield { 'text': quote.css('.text::text').get(), 'author': quote.css('.author::text').get(), 'tags': quote.css('.tag::text').getall(), } next_page = response.css('.next a::attr(href)').get() if next_page is not None: yield response.follow(next_page, self.parse)
解释:
MySpider 类继承自 scrapy.Spider。
name 属性指定了 Spider 的名称。
start_urls 属性指定了起始 URL。
parse 方法是 Spider 的核心,它负责解析网页并提取数据。
response.css 方法使用 CSS 选择器来选择元素。
yield 语句用于返回提取的数据或新的请求。
response.follow 方法用于创建新的请求,并指定回调函数。
Item Pipeline 负责处理 Spider 提取的 Items。 你可以使用 Item Pipeline 来清洗、验证和存储数据。
代码示例 (一个简单的 Item Pipeline):
# my_pipeline.py class MyPipeline: def process_item(self, item, spider): item['text'] = item['text'].strip() return item
配置 Item Pipeline (settings.py):
# settings.py ITEM_PIPELINES = { 'my_project.my_pipeline.MyPipeline': 300, }
解释:
MyPipeline 类实现了自定义 Item Pipeline。
process_item 方法在 Item 被传递给 Item Pipeline 时被调用,可以修改 Item。
ITEM_PIPELINES 设置指定了要启用的 Item Pipeline 及其优先级。
Spider 中间件可以修改进入 Spider 的请求和离开 Spider 的响应。 你可以使用 Spider 中间件来实现重试、代理、User-Agent 轮换等功能。
代码示例 (一个简单的 Spider 中间件):
# my_middleware.py class MySpiderMiddleware: def process_spider_input(self, response, spider): return None def process_spider_output(self, response, result, spider): for i in result: yield i def process_spider_exception(self, response, exception, spider): return None def process_start_requests(self, start_requests, spider): for r in start_requests: yield r
配置 Spider 中间件 (settings.py):
# settings.py SPIDER_MIDDLEWARES = { 'my_project.my_middleware.MySpiderMiddleware': 543, }
解释:
MySpiderMiddleware 类实现了自定义 Spider 中间件。
process_spider_input 方法在响应进入 Spider 之前被调用。
process_spider_output 方法在 Spider 产生 Item 或 Request 之后被调用。
process_spider_exception 方法在 Spider 发生异常时被调用。
process_start_requests 方法在 Spider 启动时被调用。
SPIDER_MIDDLEWARES 设置指定了要启用的 Spider 中间件及其优先级。
Downloader 中间件可以修改发送给下载器的请求和下载器接收到的响应。 你可以使用 Downloader 中间件来实现代理、User-Agent 轮换、重试等功能。
(Downloader Middleware 的代码示例已经在 2.3 Downloader 中提供)
Scrapy 的核心组件共同协作,构建了一个强大而灵活的爬虫框架。 理解每个组件的作用以及如何自定义它们,对于构建高效、可维护的爬虫至关重要。 通过本文提供的代码示例和详细解释,你应该能够更好地理解 Scrapy 的核心组件,并能够根据自己的需求进行定制。
希望这篇文章对你有所帮助!