在 AWS Lambda 上运行 Crawlee 浏览器爬虫:Playwright + @sparticuz/chromium 完整部署指南 在 AWS Lambda 上运行 Crawlee 浏览器爬虫Playwright sparticuz/chromium 完整部署指南【免费下载链接】crawleeCrawlee—A web scraping and browser automation library for Node.js to build reliable crawlers. In JavaScript and TypeScript. Extract data for AI, LLMs, RAG, or GPTs. Download HTML, PDF, JPG, PNG, and other files from websites. Works with Puppeteer, Playwright, Cheerio, JSDOM, and raw HTTP. Both headful and headless mode. With proxy rotation.项目地址: https://gitcode.com/GitHub_Trending/cr/crawlee导读本文讲解如何把基于 Playwright 的 Crawlee 爬虫部署到 AWS Lambda。核心挑战在于 Lambda 环境需要同时携带代码、依赖与浏览器二进制文件且文件系统只读、直接上传存在 50MB 限制。读完本文你将掌握用sparticuz/chromium管理 Chromium 二进制、以 Lambda Layer S3 方式打包依赖、通过独立Configuration让 Lambda 保持无状态、以及最终在 AWS 控制台完成部署与调参的完整流程。本文以 Crawlee 官方文档 docs/deployment/aws-browsers.md 为骨架并结合仓库源码packages/core/src/configuration.ts、packages/playwright-crawler/src/internals/playwright-launcher.ts 等做纵深剖析。为什么浏览器爬虫上 Lambda 更麻烦在 AWS Lambda 上运行普通的 Cheerio 爬虫纯 HTTP 请求无需浏览器相对简单官方文档 docs/deployment/aws-cheerio.md 介绍了相应做法。但运行浏览器驱动的爬虫如PlaywrightCrawler、PuppeteerCrawler要复杂一些核心原因有两点必须携带浏览器二进制AWS Lambda 环境不会预装 Chromium。我们要上传的不仅是业务代码和node_modules依赖还必须把浏览器可执行文件一并带入运行时。环境限制多Lambda 的文件系统是只读的唯一可写空间是/tmp且有容量上限默认 50MB 的直接上传限制运行时没有 GPU 硬件加速支持。好消息是这些障碍都有成熟的解决办法——核心思路是用 NPM 包管理浏览器二进制用 Lambda Layer 承载依赖用 S3 中转上传最后在代码层面做三处针对性修改。第一步用 sparticuz/chromium 管理浏览器二进制直接在 Lambda 里安装 Chromium 是很痛苦的但社区已经准备好了现成的 NPM 包sparticuz/chromium一个包含brotli 压缩版 Chromium 二进制的 NPM 包。在 Lambda 环境中运行时该包会自动把二进制解压到/tmp/目录并通过executablePath()返回可执行文件的路径。把它加入项目依赖然后把node_modules打包成 zip 即可# 安装 sparticuz/chromium 到 dependencies npm i -S sparticuz/chromium # 把依赖打包成 zip zip -r dependencies.zip ./node_modules:::note 为什么必须走 S3 而不是直接上传 Layer AWS 对直接上传有 50MB 的限制而压缩后的 Chromium 构建本身就接近这个大小解压后体积更大。因此不能直接把dependencies.zip作为 Lambda Layer 上传正确做法是先把dependencies.zip作为对象上传到S3在创建 Lambda Layer 时提供该 S3 对象的链接AWS 会从 S3 拉取该对象创建 Layer从而绕过直接上传的大小限制。这种做法与 Cheerio 场景下用 Layer 共享node_modules的思路一致见 docs/deployment/aws-cheerio.md区别在于浏览器爬虫的依赖体积大得多S3 中转几乎是必选项。 :::第二步改造 Crawlee 代码三处关键修改2.1 为每个爬虫传入独立的 Configuration 实例默认情况下Crawlee 的所有爬虫实例共享同一个全局存储所有爬虫共用同一个默认的 Dataset / Key-Value Store / Request Queue。这在本地开发时很方便但在 Lambda 里会带来状态泄漏AWS 会在首次执行后让容器存活一段时间以减少冷启动后续调用若复用旧实例不同请求之间的数据会互相干扰产生难以排查的 bug。解决办法是给爬虫传入一个全新的Configuration实例让每个爬虫实例拥有自己独立的存储// 更多信息见 https://crawlee.dev/ import { Configuration, PlaywrightCrawler } from crawlee; import { router } from ./routes.js; const startUrls [https://crawlee.dev]; const crawler new PlaywrightCrawler({ requestHandler: router, }, new Configuration({ persistStorage: false, // 关键关闭磁盘持久化改用内存存储 })); await crawler.run(startUrls);这里的persistStorage: false至关重要它告诉 Crawlee 使用**内存存储MemoryStorageBackend**而非文件系统存储因为 Lambda 的文件系统是只读的。源码佐证在 packages/core/src/configuration.ts 中persistStorage被定义为配置字段/** default true */ persistStorage: field(coerceBoolean.default(true), CRAWLEE_PERSIST_STORAGE),它默认值为true也可以通过环境变量CRAWLEE_PERSIST_STORAGE覆盖0或false视为假值。存储后端的选择在 packages/core/src/service_locator.ts 中实现this.#storageBackend configuration.persistStorage ? new FileSystemStorageBackend({ localDataDirectory: configuration.storageDir, logger: this.getLogger().child({ prefix: FileSystemStorageBackend }), }) : new MemoryStorageBackend({ logger: this.getLogger().child({ prefix: MemoryStorageBackend }), });也就是说persistStorage: true时数据落盘到storageDir默认./storage设为false后数据集、请求队列等全部驻留内存——这正是 Lambda 场景需要的无状态行为。从 packages/core/src/configuration.ts 还可以看到Configuration是不可变的值对象配置值在构造时一次性解析解析优先级为构造函数选项 环境变量 crawlee.json schema 默认值此外Crawlee 的爬虫构造函数支持把configuration作为服务定位器选项传入从而为每个爬虫创建作用域化的 ServiceLocator见 packages/basic-crawler/src/internals/basic-crawler.ts。这正是每个爬虫实例拥有独立存储、互不干扰的底层机制。:::tip 保持 Lambda 无状态 AWS 为了让冷启动更快会在一次执行结束后将容器环境保留一段时间。若后续调用复用同一个爬虫实例你会访问到已经被使用过的存储与状态。因此务必要么在每次调用时新建爬虫实例要么确保状态不跨调用残留。TLDR: Keep your Lambda stateless.:::2.2 注入 Chromium 可执行文件路径与启动参数第二步把sparticuz/chromium提供的可执行文件路径交给 Playwright。AWS Lambda 执行环境还缺少 GPU 加速等硬件支持可以通过把aws_chromium.args传给args参数让 Chromium 以适配 Lambda 的方式启动// 更多信息见 https://crawlee.dev/ import { Configuration, PlaywrightCrawler } from crawlee; import { router } from ./routes.js; import aws_chromium from sparticuz/chromium; const startUrls [https://crawlee.dev]; const crawler new PlaywrightCrawler({ requestHandler: router, launchContext: { launchOptions: { executablePath: await aws_chromium.executablePath(), // Lambda 内解压后的 Chromium 路径 args: aws_chromium.args, // 针对无 GPU / 只读文件系统的启动参数 headless: true } } }, new Configuration({ persistStorage: false, })); await crawler.run(startUrls);源码佐证——launchContext的透传链路launchContext.launchOptions是 Playwright 原生browserType.launch()的选项见 packages/playwright-crawler/src/internals/playwright-launcher.ts。PlaywrightLauncher在构造时会把launchOptions原样透传给底层 Playwright Plugin并确保executablePath生效const { launchOptions {}, ...rest } parsedContext; super({ ...rest, launchOptions: { ...launchOptions, executablePath: getDefaultExecutablePath(parsedContext, configuration), }, launcher, }, configuration);其中getDefaultExecutablePath的逻辑是如果调用方显式传入launchOptions.executablePath则直接采用这正是我们传入aws_chromium.executablePath()的路径否则按useChrome、CRAWLEE_DEFAULT_BROWSER_PATH的顺序回退见 playwright-launcher.ts。在 Lambda 场景中显式传入sparticuz/chromium的路径是唯一可靠的做法。PlaywrightCrawler的构造函数也会把launchContext、headless与configuration一起交给内部的浏览器池构建器见 packages/playwright-crawler/src/internals/playwright-crawler.tssuper({ ...(browserCrawlerOptions as unknown as PlaywrightCrawlerOptions...), launchContext, configuration, browserPoolBuilder: (remoteBrowser) remoteBrowser ? remotePlaywrightBrowserPool({ ...remoteBrowser, launchContext, headless, configuration }) : playwrightBrowserPool({ launchContext, headless, configuration }), contextPipelineBuilder: contextPipelineBuilder ?? (() this.buildContextPipeline()), });因此executablePath、args、headless都会沿着这条链路直达 Playwright 的浏览器启动调用。2.3 把逻辑包装进 Lambda 的 handler 函数最后把以上所有逻辑封装进导出的handler函数——这就是 AWS 将要执行的 Lambda 入口。爬虫运行结束后通过crawler.getData()取出采集到的数据作为 HTTP 响应返回import { Configuration, PlaywrightCrawler } from crawlee; import { router } from ./routes.js; import aws_chromium from sparticuz/chromium; const startUrls [https://crawlee.dev]; export const handler async (event, context) { const crawler new PlaywrightCrawler({ requestHandler: router, launchContext: { launchOptions: { executablePath: await aws_chromium.executablePath(), args: aws_chromium.args, headless: true } } }, new Configuration({ persistStorage: false, })); await crawler.run(startUrls); return { statusCode: 200, body: await crawler.getData(), }; }关于getData()它是 Dataset 的标准读取接口支持limit、offset等分页选项底层走事务感知的分页读取见 packages/core/src/storages/dataset.ts。因为设置了persistStorage: false数据来自内存中的数据集如果数据集非常大请为getData()传入合适的limit以避免响应过大。另外注意handler的第一个参数event是 AWS 传入的触发事件对象。你可以进一步解析它来参数化爬虫运行——例如把起始 URL、请求数量上限等通过事件内容动态传入。第三步部署代码到 AWS代码改造完成后部署流程如下打包代码把项目代码不含node_modules——依赖已经在 Lambda Layer 里了打包成 zipzip -r package.zip . --exclude node_modules/*上传代码包在 AWS Lambda 控制台把package.zip作为代码源上传。挂载依赖 Layer在 Lambda 配置中把之前创建的依赖 Layer含sparticuz/chromium及node_modules附加到该函数上。配置 handler 入口在 Lambda 的Runtime Settings中把 handler 指向导出主函数的位置。handler 名称使用斜杠表示目录结构、用点号表示具名导出。例如handler函数从src/main.js中导出则填写src/main.handler测试点击Test按钮发送一个示例测试事件。事件的具体内容暂时无关紧要——如前所述如需进一步参数化爬虫再解析event对象即可。第四步内存与超时配置务必调整因为这里运行的是完整版浏览器Lambda 的默认资源配置是不够的必须到 Lambda 控制台的Configuration选项卡中调整配置项建议值说明Memory内存1024 MB 或更高完整 Chromium 进程占用较高内存大小也直接影响执行速度Timeout超时视爬虫运行时长而定先在本地运行爬虫测量实际耗时再据此设置超时值:::tip 关于临时存储 如果爬虫运行中需要较大的/tmp空间例如sparticuz/chromium解压 Chromium 就要占用一部分可在 Lambda 的 Configuration 选项卡中调整Ephemeral storage大小确保解压后的浏览器二进制与运行时数据有足够的落盘空间。 :::完整工作流回顾把整个过程串起来一次成功的部署包含以下环节依赖层npm i -S sparticuz/chromium→zip -r dependencies.zip ./node_modules→ 上传 S3 → 基于 S3 对象创建 Lambda Layer代码改造独立Configuration({ persistStorage: false })→launchContext.launchOptions注入executablePath、args、headless→ 包装handler并返回crawler.getData()部署打包不含node_modules的代码 zip → 上传代码 → 挂载依赖 Layer → 设置src/main.handler→ Test 验证调参内存 ≥ 1024 MB、按本地实测设置超时、必要时调大临时存储。这套方案的姊妹篇——不依赖浏览器的 Cheerio 版本部署代码改造思路一致但无需处理浏览器二进制——参见 docs/deployment/aws-cheerio.md。两份文档配合阅读可以覆盖从纯 HTTP 到浏览器渲染的完整 Lambda 部署场景。【免费下载链接】crawleeCrawlee—A web scraping and browser automation library for Node.js to build reliable crawlers. In JavaScript and TypeScript. Extract data for AI, LLMs, RAG, or GPTs. Download HTML, PDF, JPG, PNG, and other files from websites. Works with Puppeteer, Playwright, Cheerio, JSDOM, and raw HTTP. Both headful and headless mode. With proxy rotation.项目地址: https://gitcode.com/GitHub_Trending/cr/crawlee创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考