Crawlee 在 AWS Lambda 上运行 Playwright 爬虫:浏览器二进制、存储与部署完整指南

📅 发布时间:2026/9/13 0:49:23
Crawlee 在 AWS Lambda 上运行 Playwright 爬虫:浏览器二进制、存储与部署完整指南
Crawlee 在 AWS Lambda 上运行 Playwright 爬虫浏览器二进制、存储与部署完整指南【免费下载链接】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导读本文基于 Crawlee 官方部署文档系统讲解如何在 AWS Lambda 这一无服务器环境中运行 Playwright 浏览器爬虫。核心难点在于 Lambda 的函数包无法直接携带浏览器二进制文件且运行时文件系统只读、内存受限。读完本文你将掌握通过sparticuz/chromium与 Lambda Layer 管理 Chromium 二进制的完整链路学会为 Crawlee 配置独立的ConfigurationpersistStorage: false以保证无状态运行并了解内存、超时等关键调优参数。为什么在 AWS Lambda 上跑浏览器爬虫比较棘手在本地或常规服务器上Crawlee 的 Playwright 爬虫可以直接使用 Playwright 自行下载的浏览器二进制。但 AWS Lambda 的运行环境有三个先天约束让这件事变得有点复杂但并非不可能原文档的定位函数包体积限制上传的代码压缩包有体积上限直接上传约 50MB而完整的 Chromium 二进制本身就在这个量级附近更别说还要加上node_modules只读文件系统Lambda 运行时的文件系统除/tmp/目录外是只读的浏览器二进制无法像本地那样写到任意路径无状态运行环境Lambda 会在一次执行后把容器环境保留一段时间以降低冷启动延迟如果爬虫实例和存储状态被复用就会出现难以排查的状态残留问题。Crawlee 本身是纯 Node.js 的爬虫库代码层面并不区分运行环境因此上述问题全部需要由部署方案来解决浏览器二进制走 Lambda Layer代码存储走内存爬虫实例每次执行重新创建。第一步管理浏览器二进制——sparticuz/chromium Lambda Layer用 NPM 包携带 ChromiumCrawlee 官方推荐借助现成的 NPM 包来管理浏览器二进制的安装sparticuz/chromium一个内置brotli 压缩 Chromium 二进制的 NPM 包。当它在 Lambda 环境中运行时会先把压缩的二进制解压到/tmp/路径下并返回可执行文件的路径。这个包的设计恰好规避了 Lambda 的两个约束压缩包在部署时占空间小运行时解压到可写的/tmp/再通过executablePath()把路径交给 Playwright。只需要把这个包加入项目依赖并把node_modules打包即可# 安装依赖包 npm i -S sparticuz/chromium # 打包依赖用于上传为 Lambda Layer zip -r dependencies.zip ./node_modules为什么不能直接上传 LayerAWS 对直接上传到 Lambda Layer 的内容有50MB 的体积限制而压缩后的 Chromium 构建本身就接近这个大小直接上传很可能超限。因此正确做法是先把dependencies.zip上传到S3 存储桶在创建 Lambda Layer 时选择从 S3 上传提供该对象的链接Lambda 会从 S3 拉取并挂载这个 Layer。这样 Layer 的创建过程不再受 50MB 直接上传限制约束同时 Layer 还可以在多个 Lambda 函数之间共享把每个函数自身的代码包保持精简。关于无服务器 Chromium 的补充谨慎表述需要说明的是sparticuz/chromium是社区中广泛使用的无服务器 Chromium 方案Crawlee 官方文档明确引用了它作为推荐路径。它的核心价值在于把压缩 → 上传 → 运行时解压 → 返回可执行路径这一流程封装成开箱即用的 NPM 包。如果你希望完全自行掌控也可以手动完成下载 Linux 版 Chromium → brotli 压缩 → 放入 Layer → 运行时解压的等价步骤但维护成本会高很多。第二步改造 Crawlee 代码传递独立的Configuration实例在 Lambda 中每个爬虫实例都要拥有自己的存储避免与其他并发实例互相干扰。原文档给出的做法是在构造PlaywrightCrawler时把第二个参数从默认的全局配置替换为一个全新的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的底层含义可以从仓库源码得到印证在 packages/core/src/configuration.ts 中配置项定义为persistStorage: field(coerceBoolean.default(true), CRAWLEE_PERSIST_STORAGE)即默认值为true且可被环境变量CRAWLEE_PERSIST_STORAGE覆盖在同一文件的配置优先级说明中明确写道constructor options environment variables crawlee.json schema defaults构造函数选项 环境变量 crawlee.json 配置文件 模式默认值。因此这里通过构造函数传入false拥有最高优先级会稳定地关闭持久化存储改为纯内存存储适配 Lambda 只读文件系统Configuration对象是**不可变immutable**的——从 registerAccessors 的实现可以看到所有字段只注册了 getter任何赋值都会抛出TypeError: Configuration is immutable所以配置必须在构造时一次性定好。你还可以用环境变量CRAWLEE_PERSIST_STORAGEfalse达到同样的效果这在不想改动代码、只想通过 Lambda 环境变量配置时更灵活。注入 Chromium 可执行路径与启动参数sparticuz/chromium包能返回解压后的可执行文件路径同时AWS Lambda 的执行环境缺少 GPU 加速等硬件支持需要通过启动参数告诉 Chromium。把这两点合并到launchContext.launchOptions中// 更多信息见 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(), args: aws_chromium.args, headless: true } } }, new Configuration({ persistStorage: false, }));各参数含义executablePathsparticuz/chromium解压 Chromium 后返回的可执行文件绝对路径Playwright 将直接使用该二进制而不是自行下载的版本argsaws_chromium.args是一组为 AWS Lambda 环境准备的 Chromium 启动参数例如禁用 GPU、规避无沙箱环境的报错等原文档要求必须原样传入headless: trueLambda 中不存在显示器必须使用无头模式。从源码看这个注入点在 Playwright 启动链路的根部packages/playwright-crawler/src/internals/playwright-launcher.ts 中会把launchContext.launchOptions与默认executablePath合并后交给底层BrowserLauncher其中getDefaultExecutablePath同文件 L133-L153的逻辑是如果用户在launchOptions里显式指定了executablePath则优先采用用户值这正是我们在 Lambda 场景下注入sparticuz/chromium路径时实际生效的分支。换句话说这里传入的executablePath会覆盖 Crawlee 的任何默认浏览器解析逻辑。把全部逻辑包进handler并返回数据最后把所有代码包进导出的handler函数——这就是 AWS Lambda 将要执行的入口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(), }; }crawler.getData()会把本次爬取写入默认 Dataset 的数据读取出来放进响应体的body中这样外部调用方API Gateway、EventBridge 或直接调用就能拿到结构化抓取结果。无状态原则重要AWS 在首次执行后会将环境保留一段时间以减少冷启动因此后续每次 Lambda 调用都可能复用上一次的容器。如果爬虫实例被复用会访问到已运行过的实例导致脏数据与难以定位的问题。务必保证每次调用都新建 crawler 实例、每次调用都新建Configuration——即让 Lambda 保持无状态。这也是原文档在无浏览器场景如 Cheerio on AWS Lambda中反复强调的同一原则TLDR: Keep your Lambda stateless.路由与请求处理器的组织方式示例代码中的router来自项目模板里的routes.js通常是一个由createRouter创建的请求分发器。例如// src/routes.js import { createPlaywrightRouter } from crawlee; export const router createPlaywrightRouter(); router.addDefaultHandler(async ({ page, enqueueLinks, log }) { log.info(抓取页面: ${page.url()}); // 在这里用 page.locator() 等 API 提取数据 });requestHandler: router会把所有抓取到的请求交给这个分发器处理。你可以参考仓库中的 PlaywrightCrawler 基础示例 和 Crawl multiple URLsPlaywright 了解更完整的 handler 与路由写法。第三步部署到 AWS Lambda打包代码代码侧只打包业务代码不含node_modules因为依赖已经放进了 Layerzip -r package.zip .然后在 AWS 控制台创建 Lambda 函数上传package.zip作为代码源在Layers配置中附加之前创建的dependenciesLayer包含node_modules与sparticuz/chromium的 Layer在Runtime settings中设置 handler 名称。handler 是src/main.js中导出的handler函数因此填入src/main.handler用/表示目录层级用.表示命名导出点击Test发送一个测试事件。事件内容此时无关紧要——如果你想进一步参数化爬虫比如把起始 URL 放进事件可以解析 AWS 作为第一个参数传入 handler 的event对象。内存与超时设置原文档重点提示使用完整尺寸的浏览器意味着 Lambda 配置必须调整原文档给出两条硬性建议内存设置为 1024 MB 或更多。浏览器进程的内存占用远超纯 HTTP 爬虫内存不足会直接导致 Lambda 被杀进程更新 Lambda 超时时间。超时值取决于你的爬虫运行时长先在本地运行爬虫测量实际执行时间再据此设置超时留出合理余量。除此之外在 AWS Lambda 控制台的Configuration页签里你还可以调整ephemeral storage临时存储大小——/tmp/目录就来自这块空间而sparticuz/chromium要把压缩的浏览器解压到这里因此临时存储过小同样会导致运行失败。原文档提醒内存大小会显著影响 Lambda 的执行速度更多内存通常对应更强的 CPU 配额需要在实际成本与性能之间权衡。完整工作流回顾把整个方案串起来一次完整的部署流程是npm i -S sparticuz/chromium安装浏览器二进制包zip -r dependencies.zip ./node_modules打包依赖将dependencies.zip上传到 S3并以 S3 对象为来源创建 Lambda Layer规避 50MB 直接上传限制改造代码传入独立Configuration({ persistStorage: false })→ 注入executablePath与aws_chromium.args→ 包进handler并返回crawler.getData()zip -r package.zip .打包业务代码并上传为 Lambda 函数代码附加依赖 Layer设置 handler 为src/main.handler在 Configuration 中把内存设为 ≥1024MB、按需调整超时与临时存储Test 触发验证返回的statusCode: 200与抓取数据。如果只是做纯 HTTP 抓取而不需要浏览器渲染可以改用 Cheerio 方案部署会更轻量无需 Layer、无需浏览器二进制参见 Cheerio on AWS Lambda若仍想用浏览器但需要更精细的资源控制也可以参考 GCP 上的浏览器部署文档 对比不同云平台的差异。【免费下载链接】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),仅供参考