Apify/Crawlee项目中的结果存储机制详解
引言
在Web爬虫开发中,如何高效地存储和管理爬取结果是一个关键问题。Apify/Crawlee项目提供了一套完善的结果存储系统,可以帮助开发者轻松处理各种类型的数据。本文将深入解析Crawlee中的存储机制,包括键值存储(Key-value Store)和数据集(Dataset)两种核心存储类型。
存储基础配置
Crawlee的存储系统默认将数据保存在本地磁盘上,存储位置由CRAWLEE_STORAGE_DIR
环境变量决定。如果未设置该变量,默认会使用当前工作目录下的./storage
文件夹。
整个存储系统由MemoryStorage
类管理,采用内存和本地文件双重存储策略:爬虫运行期间,所有信息既保存在内存中,也会同步写入本地文件的相应存储目录。
键值存储(Key-value Store)
基本概念
键值存储是一种灵活的数据存储方式,适合保存各种类型的数据记录或文件。每个数据记录都有唯一的键(key)和对应的MIME内容类型。这种存储特别适合保存网页截图、PDF文档或爬虫状态等场景。
默认键值存储
每个Crawlee项目运行都会关联一个默认键值存储。按照约定,项目输入和输出分别存储在默认键值存储的INPUT
和OUTPUT
键下。虽然通常输入输出都是JSON格式,但实际上支持任何文件格式。
存储路径结构
键值存储的数据按照以下路径结构保存:
{CRAWLEE_STORAGE_DIR}/key_value_stores/{STORE_ID}/{KEY}.{EXT}
{STORE_ID}
:键值存储的名称或ID,默认存储的ID为default
{KEY}
:数据记录的键名{EXT}
:根据MIME类型确定的文件扩展名
使用示例
import { KeyValueStore } from 'crawlee';
// 从默认键值存储获取INPUT
const input = await KeyValueStore.getInput();
// 向默认键值存储写入OUTPUT
await KeyValueStore.setValue('OUTPUT', { myResult: 123 });
// 打开一个命名键值存储
const store = await KeyValueStore.open('some-name');
// 写入记录(自动转换JSON)
await store.setValue('some-key', { foo: 'bar' });
// 读取记录(自动解析JSON)
const value = await store.getValue('some-key');
// 删除记录
await store.setValue('some-key', null);
数据集(Dataset)
基本概念
数据集用于存储结构化数据,其中每个对象具有相同的属性,如电商产品或房地产信息。可以将其想象为一个表格,每个对象是一行,其属性是列。数据集是仅追加(append-only)的存储,只能添加新记录,不能修改或删除现有记录。
默认数据集
每个Crawlee项目运行都会关联一个默认数据集,通常用于存储特定于爬虫运行的结果。使用它是可选的。
存储路径结构
数据集按照以下路径结构保存:
{CRAWLEE_STORAGE_DIR}/datasets/{DATASET_ID}/{INDEX}.json
{DATASET_ID}
:数据集的名称或ID,默认数据集的ID为default
{INDEX}
:数据项在数据集中的从零开始的索引
使用示例
import { Dataset } from 'crawlee';
// 向默认数据集写入单行数据
await Dataset.pushData({ col1: 123, col2: 'val2' });
// 打开一个命名数据集
const dataset = await Dataset.open('some-name');
// 写入单行数据
await dataset.pushData({ foo: 'bar' });
// 写入多行数据
await dataset.pushData([
{ foo: 'bar2', col2: 'val2' },
{ col3: 123 }
]);
存储清理机制
自动清理
默认情况下,Crawlee会在爬虫启动前清理默认存储(除非另有指定)。这种清理会在以下情况之一发生时触发:
- 显式打开某个存储(如
Dataset.open()
) - 通过辅助方法使用默认存储(如
Dataset.pushData()
内部会调用Dataset.open()
) - 执行爬虫的
run
方法时
手动清理
如果需要提前清理存储,可以使用purgeDefaultStorages()
辅助函数:
import { purgeDefaultStorages } from 'crawlee';
await purgeDefaultStorages();
此函数会清理默认结果存储目录,但会保留默认键值存储目录中的INPUT
键。它实际上是调用了底层存储实现的purge
方法,并确保在给定的执行上下文中只清理一次,因此可以安全地多次调用。
最佳实践建议
-
合理选择存储类型:对于非结构化数据或文件,使用键值存储;对于结构化数据,使用数据集。
-
命名存储管理:对于大型项目,建议使用命名存储而非默认存储,以便更好地组织数据。
-
输入输出规范:遵循约定,将输入放在
INPUT
键,输出放在OUTPUT
键,保持项目一致性。 -
性能考虑:频繁的小数据写入可能影响性能,考虑批量处理数据后再写入。
-
存储清理:在开发阶段可以利用自动清理功能,但在生产环境可能需要更精细的控制。
通过合理利用Crawlee提供的存储机制,开发者可以专注于业务逻辑的实现,而无需过多担心数据存储和管理的问题。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考