Crawlee CheerioCrawler 部署到 GCP Cloud Functions:完整改造与实战指南
2026/9/13 1:22:36 网站建设 项目流程

Crawlee CheerioCrawler 部署到 GCP Cloud Functions:完整改造与实战指南

【免费下载链接】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 的CheerioCrawler基于纯 HTTP 请求与 Cheerio 解析器工作,不依赖浏览器进程,因此非常适合运行在 Google Cloud Functions 这类轻量 FaaS 平台上。本文以仓库 gcp-cheerio.md 为骨架,逐步讲解如何把本地 Crawlee 项目改造成可在 GCP Cloud Functions 中运行并返回抓取数据的形态,同时结合仓库源码说明persistStorageConfiguration等关键机制背后的实现原理。读完本文,你将掌握「改造项目 → ZIP 上传部署 → 在线测试」的完整流程。

为什么需要改造:Cloud Functions 的环境约束

在本地开发时,Crawlee 默认会把数据集、请求队列、键值存储等内容持久化到磁盘上的storage目录,方便断点续爬与调试。但 GCP Cloud Functions 是典型的无状态 FaaS 环境,它具备以下特点,决定了我们不能直接原样上传本地项目:

  • 无持久化文件系统保障:函数实例的生命周期短且随时可能被回收,依赖磁盘的存储方案不可靠;
  • 实例可能被复用:函数执行结束后容器可能存活一段时间以降低冷启动延迟,残留的内存状态会污染下一次调用;
  • 无 Layers 机制:与 AWS Lambda 不同,GCP Cloud Functions 不支持把依赖打包成单独的 Layer,而是根据package.json自动安装依赖(详见下文「部署」一节);
  • 以 HTTP 请求触发:函数通过触发器接收请求并返回响应,抓取逻辑必须包裹在符合平台约定的入口函数中。

因此改造工作只需要两件事:关闭磁盘持久化(改用内存存储),以及把爬虫逻辑包裹进一个可导出的 handler 函数

第一步:创建项目并设置入口文件

在本地执行脚手架命令创建 Crawlee 项目:

npx crawlee create

创建完成后,修改项目根目录下的package.json,把main字段指向src/main.js。GCP Cloud Functions 会依据该字段定位入口模块:

{ "name": "my-crawlee-project", "version": "1.0.0", "main": "src/main.js", ... }

仓库内置的 Cheerio TypeScript 模板(见 packages/templates/templates/cheerio-ts/package.json)展示了标准项目结构:源码位于src/下,包含main.ts与路由文件,start:dev使用tsx运行、start:prod运行编译产物。如果你选用 TypeScript,部署前需先执行构建,并把入口指向编译后的dist/main.js;本文按文档使用 JavaScript 版本。

第二步:传入独立 Configuration 并关闭持久化存储

打开src/main.js,需要做的第一个改动是:给爬虫构造函数传入一个独立的Configuration实例,并设置persistStorage: false

import { CheerioCrawler, Configuration } 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);

为什么必须是「独立」的 Configuration

Crawlee 默认维护一个全局共享的配置单例(Configuration.getGlobalConfiguration(),见 packages/core/src/configuration.ts),所有爬虫实例默认共享同一套存储。在本地开发这很便利,但在 FaaS 环境下会导致「状态残留」:上一次调用写入的数据会被下一次调用读到,引发极难排查的偶发问题。因此每次运行都要通过构造函数传入全新的Configuration实例,保证调用之间相互隔离、函数保持无状态。

persistStorage: false 的底层机制

从源码看,persistStorage是 Crawlee 核心配置字段之一,默认值为true,并可通过环境变量CRAWLEE_PERSIST_STORAGE覆盖(见 configuration.ts)。它的作用体现在存储后端的选型上:在 service_locator.ts 中,getStorageBackend()会根据配置决定创建哪种存储后端——

  • persistStorage: true(默认)→FileSystemStorageBackend,数据落盘到storageDir指定的目录(默认./storage);
  • persistStorage: falseMemoryStorageBackend,数据仅保存在内存中,函数结束即释放。

配置解析遵循「构造函数选项 > 环境变量 > crawlee.json > schema 默认值」的优先级链(见 configuration.ts),且Configuration一旦创建便不可变更(对属性的赋值会抛出TypeError,见 configuration.ts),因此所有选项必须在构造时一次传齐。

提示:如果不想改代码,也可以在 GCP 控制台中为函数设置环境变量CRAWLEE_PERSIST_STORAGE=false达到同样效果;但显式传入Configuration更清晰,也避免了共享全局状态。

第三步:包裹 handler 函数并返回数据

第二个改动是把爬虫调用包裹进一个handler 函数,并将其从src/main.js以**命名导出(named export)**的方式暴露。该函数需要满足:

  • 可以是异步函数(async);
  • 接收两个位置参数:req(包含用户请求 Cloud Function 的详细信息)和res(可修改的响应对象);
  • 通过res.send(data)返回数据。
import { CheerioCrawler, Configuration } from 'crawlee'; import { router } from './routes.js'; const startUrls = ['https://crawlee.dev']; export const handler = async (req, res) => { const crawler = new CheerioCrawler({ requestHandler: router, }, new Configuration({ persistStorage: false, })); await crawler.run(startUrls); return res.send(await crawler.getData()) }

这里有两个关键点值得展开:

  1. crawler.getData():爬虫运行结束后,抓取结果会写入默认数据集(Dataset)。由于persistStorage: false,数据集只存在于内存中,函数返回前调用getData()取出全部结果,并通过res.send()以 JSON 形式返回给调用方。
  2. 每次调用都新建爬虫实例:把new CheerioCrawler(...)放在 handler 内部而非模块顶层,确保每次函数调用都从零开始。这与 AWS Lambda 场景下的建议完全一致——平台会在首次执行后保留运行环境一段时间以降低冷启动,若爬虫实例被复用,数据集、会话池等状态就会在多次调用间泄漏(可对照仓库中 aws-cheerio.md 的「Keep your Lambda stateless」提示)。

补充CheerioCrawler在仓库中的实现位于 packages/cheerio-crawler/src/internals/cheerio-crawler.ts,它继承自DOMCrawler(位于@crawlee/http包),构造函数将所有选项透传给父类并注入 Cheerio 解析器。也就是说,本指南的改造思路同样适用于其他基于 HTTP 的爬虫变体(如HttpCrawlerJsdomCrawler等);浏览器类爬虫在 GCP 上则需要改走 Cloud Run 容器方案,详见仓库中的 gcp-browsers.md。

第四步:部署到 Google Cloud Platform

1. 创建并配置函数

在 Google Cloud 控制台进入 Cloud Functions,创建一个新函数,并按需配置:

  • 内存与 CPU:根据目标网站的响应体大小与并发量分配,Cheerio 爬虫不加载浏览器,通常不需要大内存,但抓取大页面时可适当提高;
  • 区域(Region):选择离目标站点较近的区域以降低网络延迟;
  • 函数超时(Timeout):Cloud Functions 默认超时较短,需要根据一次抓取任务的总耗时上调。

2. 选择 ZIP 上传

部署方式选择ZIP Upload。在此之前需要创建一个 GCP 存储桶(Storage Bucket),用于存放上传的 zip 包。

3. 打包项目文件

打包时排除node_modules文件夹。这是与 AWS Lambda 的关键差异:GCP Cloud Functions 没有类似 Lambda Layers 的机制,但它会在部署时根据package.json自动安装依赖。因此 zip 包只需包含源码与清单文件,例如:

zip -r my-function.zip . -x "node_modules/*"

4. 设置 Entry point

在函数配置中,将Entry point设置为从src/main.js导出的函数名——即上文的handler。GCP 会根据package.jsonmain字段定位到src/main.js,再从该模块中查找与 Entry point 同名的导出函数。

第五步:测试函数

部署完成后,在函数详情页点击Testing(测试)标签页。该页会生成一段调用 Cloud Function 的curl脚本,直接运行即可验证函数是否按预期返回抓取数据。

如果你不想在本地安装gcloudCLI,可以点击测试页面上方的 Cloud Shell 链接,在浏览器内的云端终端中直接运行这段curl脚本,无需任何本地环境准备。

常见问题与最佳实践

  • 保持函数无状态:不要把爬虫实例、Configuration、数据集引用放在模块顶层;所有状态都应在 handler 内部创建,调用结束即销毁。
  • 结果即响应:由于persistStorage: false,数据不会落盘,必须在 handler 内通过getData()取出并res.send()返回,否则数据将随实例销毁而丢失。
  • 超时与内存:抓取大型站点时,请确保函数超时设置覆盖整个爬取过程;若遇超时,可拆分为多次调用或考虑迁移到 Cloud Run 容器方案(gcp-browsers.md)。
  • 与 AWS Lambda 的差异:AWS 版指南要求打包时包含node_modules(或改用 Lambda Layers),而 GCP 版要求排除它;两者都要求persistStorage: false和「每次调用新建爬虫实例」,这说明无状态原则是所有 FaaS 平台通用的核心约束。
  • 进一步参数化:handler 的req参数携带用户请求信息,可以根据请求内容动态决定startUrls或抓取深度,把 Cloud Function 变成一个可复用的抓取 API。

总结

把 Crawlee 的CheerioCrawler项目部署到 GCP Cloud Functions,只需三步:设置main字段、传入带persistStorage: false的独立Configuration、把爬虫逻辑包裹进命名导出的handler函数并返回getData()结果。底层来看,persistStorage: false会让存储后端从FileSystemStorageBackend切换为MemoryStorageBackend,从而适配无状态、无持久化磁盘的 FaaS 环境。整个改造轻量且可复制,是 GCP 上运行轻量级 HTTP 抓取任务的务实方案。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询