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

Cheerio на AWS Lambda

Хотя локально мы можем легко создать проект Crawlee с помощью npx crawlee create, для запуска на AWS Lambda потребуются некоторые изменения.

Изменение кода

При создании нового краулера необходимо передавать уникальный экземпляр Configuration. По умолчанию все краулеры Crawlee используют общее хранилище - это удобно локально, но может вызвать проблемы с состоянием Lambda-функции.

Также при создании Configuration важно указать параметр persistStorage: false. Это указывает Crawlee использовать хранилище в памяти, так как файловая система Lambda доступна только для чтения.

src/main.js
// Подробнее на https://crawlee.dev/
import { CheerioCrawler, Configuration, ProxyConfiguration } from 'crawlee';
import { router } from './routes.js';

const startUrls = ['https://crawlee.dev'];

const crawler = new CheerioCrawler({
requestHandler: router,
}, new Configuration({
persistStorage: false,
}));

await crawler.run(startUrls);

Теперь обернем всю логику в функцию handler. Это и есть Lambda-функция, которую будет выполнять AWS.

src/main.js
// Подробнее на https://crawlee.dev/
import { CheerioCrawler, Configuration } from 'crawlee';
import { router } from './routes.js';

const startUrls = ['https://crawlee.dev'];

export const handler = async (event, context) => {
const crawler = new CheerioCrawler({
requestHandler: router,
}, new Configuration({
persistStorage: false,
}));

await crawler.run(startUrls);
};
Важно

Всегда создавайте новый экземпляр краулера для каждой Lambda-функции. AWS сохраняет среду выполнения некоторое время после первого запуска Lambda (для уменьшения времени холодного старта) - поэтому последующие вызовы будут использовать уже существующий экземпляр краулера.

Коротко: Lambda-функция должна быть без состояния.

И наконец, нужно вернуть собранные данные из Lambda после завершения работы краулера.

В итоге ваш скрипт main.js должен выглядеть примерно так:

src/main.js
// Подробнее на https://crawlee.dev/
import { CheerioCrawler, Configuration } from 'crawlee';
import { router } from './routes.js';

const startUrls = ['https://crawlee.dev'];

export const handler = async (event, context) => {
const crawler = new CheerioCrawler({
requestHandler: router,
}, new Configuration({
persistStorage: false,
}));

await crawler.run(startUrls);

return {
statusCode: 200,
body: await crawler.getData(),
}
};

Развертывание проекта

Теперь пора развернуть наш скрипт на AWS!

Создадим ZIP-архив проекта (включая папку node_modules), выполнив команду zip -r package.zip . в папке проекта.

Большая папка node_modules?

AWS имеет ограничение в 50МБ для прямой загрузки файлов. Обычно проекты Crawlee не достигают этого лимита, но с большим количеством зависимостей это возможно.

Лучший способ установки зависимостей - использование Lambda Layers. С помощью слоев можно также делиться файлами между несколькими Lambda-функциями и сохранять сам код максимально компактным.

Для создания Lambda Layer необходимо:

  • Упаковать папку node_modules в отдельный ZIP-файл (архив должен содержать одну папку с именем node_modules)
  • Создать новый Lambda Layer из этого архива. Вероятно, потребуется загрузить файл в AWS S3 и создать Layer оттуда
  • После создания просто указать использование этого слоя в Lambda-функции

Для развертывания кода загружаем архив package.zip как исходный код.

В настройках Runtime указываем handler на главную функцию краулера. Используйте слеши для описания структуры каталогов и точку для именованного экспорта. Наша функция называется handler и экспортируется из src/main.js, поэтому укажем src/main.handler.

Готово! Нажав кнопку Test, можно отправить тестовое событие в новую Lambda-функцию. Содержимое события пока не важно - при желании можно параметризовать работу краулера, анализируя объект event, который AWS передает первым аргументом в handler.

подсказка

На вкладке Configuration в панели управления AWS Lambda можно настроить объем памяти и размер временного хранилища.

Объем памяти может существенно влиять на скорость выполнения Lambda.

Подробнее о том, как производительность и стоимость масштабируются с увеличением памяти, смотрите в официальной документации.