Перейти к основному содержимому

Сохранение данных

Процесс извлечения данных не будет полным без их сохранения для дальнейшего использования и обработки. Вы подошли к финальной и самой важной части этого руководства, поэтому будьте особенно внимательны!

Для начала добавьте новый импорт в начало файла:

import { PlaywrightCrawler, Dataset } from 'crawlee';

Затем замените вызов console.log(results) на:

await Dataset.pushData(results);

и это всё. В этот раз мы не шутим. Действительно, это всё что нужно. Вот как выглядит финальный код:

Run on
import { PlaywrightCrawler, Dataset } from 'crawlee';

const crawler = new PlaywrightCrawler({
requestHandler: async ({ page, request, enqueueLinks }) => {
console.log(`Processing: ${request.url}`);
if (request.label === 'DETAIL') {
const urlPart = request.url.split('/').slice(-1); // ['sennheiser-mke-440-professional-stereo-shotgun-microphone-mke-440']
const manufacturer = urlPart[0].split('-')[0]; // 'sennheiser'

const title = await page.locator('.product-meta h1').textContent();
const sku = await page.locator('span.product-meta__sku-number').textContent();

const priceElement = page
.locator('span.price')
.filter({
hasText: '$',
})
.first();

const currentPriceString = await priceElement.textContent();
const rawPrice = currentPriceString.split('$')[1];
const price = Number(rawPrice.replaceAll(',', ''));

const inStockElement = page
.locator('span.product-form__inventory')
.filter({
hasText: 'In stock',
})
.first();

const inStock = (await inStockElement.count()) > 0;

const results = {
url: request.url,
manufacturer,
title,
sku,
currentPrice: price,
availableInStock: inStock,
};

await Dataset.pushData(results);
} else if (request.label === 'CATEGORY') {
// Мы теперь на странице категории. Мы можем использовать это для пролистывания и добавления в очередь всех товаров,
// а также любых последующих страниц, которые мы найдем

await page.waitForSelector('.product-item > a');
await enqueueLinks({
selector: '.product-item > a',
label: 'DETAIL', // <= обратите внимание на другую метку
});

// Теперь нам нужно найти кнопку "Следующая" и добавить следующую страницу результатов (если она существует)
const nextButton = await page.$('a.pagination__next');
if (nextButton) {
await enqueueLinks({
selector: 'a.pagination__next',
label: 'CATEGORY', // <= обратите внимание на ту же метку
});
}
} else {
// Это значит, что мы на начальной странице, без метки.
// На этой странице мы просто хотим добавить в очередь все страницы категорий

await page.waitForSelector('.collection-block-item');
await enqueueLinks({
selector: '.collection-block-item',
label: 'CATEGORY',
});
}
},

// Давайте ограничим наши краулинг, чтобы наши тесты были короче и безопаснее.
maxRequestsPerCrawl: 50,
});

await crawler.run(['https://warehouse-theme-metal.myshopify.com/collections']);

Что такое Dataset.pushData()

Dataset.pushData() - это функция, которая сохраняет данные в стандартный Dataset. Dataset - это хранилище, спроектированное для хранения данных в табличном формате. Каждый вызов Dataset.pushData() создает новую строку в таблице, где имена свойств выступают в роли заголовков столбцов. В стандартной конфигурации строки представлены в виде JSON-файлов, сохраненных на вашем диске, но Crawlee также поддерживает подключение других систем хранения.

Автоматическая инициализация Dataset в Crawlee

При каждом запуске Crawlee автоматически создается стандартный Dataset, поэтому нет необходимости его инициализировать или создавать экземпляр вручную. Вы можете создавать столько датасетов, сколько нужно, и даже давать им имена. Подробнее об этом можно узнать в руководстве по хранению результатов и в описании функции Dataset.open().

Где найти сохраненные данные

Если вы не меняли локальную конфигурацию Crawlee (что говорило бы о том, что вы уже знаете, что делаете, и это руководство вам не нужно), вы найдете свои данные в директории storage, которую Crawlee создает в рабочей директории запущенного скрипта:

{PROJECT_FOLDER}/storage/datasets/default/

В этой папке будут храниться все ваши сохраненные данные в пронумерованных файлах, в том порядке, в котором они были добавлены в датасет. Каждый файл представляет собой один вызов Dataset.pushData() или одну строку таблицы.

Варианты хранения данных в одном файле

Если вы хотите хранить данные в одном большом файле вместо множества маленьких, ознакомьтесь с разделом о Key-value хранилищах в руководстве по хранению результатов.

Следующие шаги

Далее вы узнаете о некоторых улучшениях, которые можно внести в код вашего краулера, чтобы сделать его более читаемым и удобным для поддержки в долгосрочной перспективе.