使用 Crawlee + PlaywrightCrawler + Camoufox 搭建防屏蔽爬虫的 TypeScript 模板实战
2026/9/12 6:25:58 网站建设 项目流程

使用 Crawlee + PlaywrightCrawler + Camoufox 搭建防屏蔽爬虫的 TypeScript 模板实战

【免费下载链接】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 官方模板camoufox-ts展开,讲解如何以 TypeScript 快速搭建一套"生产就绪"的防屏蔽爬虫项目:用PlaywrightCrawler驱动 Firefox 内核的 Camoufox 隐身浏览器,并通过 Impit HTTP 客户端与可配置的浏览器池(BrowserPool)完成网页抓取、链接入队与数据落盘。读完本文,你将掌握该模板的完整文件结构、每个配置项的底层作用,以及如何将其扩展为带代理轮换、指纹关闭、Cloudflare 挑战处理等能力的实战工程。

模板是什么:Camoufox 版 PlaywrightCrawler 脚手架

Crawlee 在 packages/templates 中维护了一批官方模板,camoufox-ts是其中专门面向反屏蔽场景的 TypeScript 模板。在 manifest.json 中,它的注册描述是 "Camoufox-based PlaywrightCrawler template project [TypeScript]",与playwright-tspuppeteer-ts等模板并列,文件清单包含src/main.tssrc/routes.tsDockerfilepackage.jsontsconfig.json等。

模板目录的完整结构如下:

packages/templates/templates/camoufox-ts/ ├── src/ │ ├── main.ts # 爬虫入口:PlaywrightCrawler 配置与运行 │ └── routes.ts # 请求路由:默认处理器 + detail 处理器 ├── Dockerfile # 基于 camoufox 镜像的多阶段构建 ├── README.md ├── package.json # 依赖与 npm 脚本 └── tsconfig.json # TypeScript 编译配置

其核心组合是三条技术线的交汇:

  • Crawlee 的PlaywrightCrawler:负责请求队列、并发控制、会话池、数据存储等爬虫基础设施;
  • Camoufox(通过camoufox-js接入):一个为网页抓取而生的隐身定制版 Firefox,提供高度拟真的浏览器指纹;
  • Imitp HTTP 客户端(@crawlee/impit-client:处理页面资源请求层面的 HTTP/TLS 指纹模拟。

在 Crawlee 官方防屏蔽指南 docs/guides/avoid_blocking.mdx 中,Camoufox 被明确推荐用于绕过 Cloudflare 一类的人机挑战:配合handleCloudflareChallengeHook后置导航钩子,可以自动模拟真实用户操作完成挑战,并在挑战通过后重载页面、把新鲜响应回传爬取上下文。模板camoufox-ts正是这一方案的最小可运行载体。

入口文件 main.ts:爬虫的核心装配

模板入口 src/main.ts 完整展示了 PlaywrightCrawler 与 Camoufox 的装配方式,代码如下(为便于讲解分段展示)。

1. 依赖导入

import { Browser, ImpitHttpClient } from '@crawlee/impit-client'; import { launchOptions } from 'camoufox-js'; import { PlaywrightCrawler, playwrightBrowserPool, ProxyConfiguration } from 'crawlee'; import { firefox } from 'playwright'; import { router } from './routes.js';
  • @crawlee/impit-client提供ImpitHttpClient与浏览器枚举Browser。这里将 HTTP 客户端指定为 Firefox 形态(Browser.Firefox),让请求层的 TLS/HTTP 指纹与页面层保持一致;
  • camoufox-js导出launchOptions(),用于生成 Camoufox 专属的浏览器启动参数;
  • crawlee包导出PlaywrightCrawlerplaywrightBrowserPoolProxyConfiguration
  • 路由从./routes.js导入(注意模板使用 NodeNext 模块解析,源码.ts内以.js后缀引用)。

2. 起点 URL 与爬虫实例

const startUrls = ['https://crawlee.dev']; const crawler = new PlaywrightCrawler({ // proxyConfiguration: new ProxyConfiguration({ proxyUrls: ['...'] }), httpClient: new ImpitHttpClient({ browser: Browser.Firefox }), requestHandler: router, // Comment this option to scrape the full website. maxRequestsPerCrawl: 20, browserPool: playwrightBrowserPool({ ... }), });

值得注意的几个配置:

  • proxyConfiguration:默认被注释掉。需要代理轮换时,取消注释并填入proxyUrls(如['http://user:pass@host:port'])即可,ProxyConfiguration@crawlee/core的 proxy_configuration.ts 实现,支持直接 URL 列表、Apify 代理与自定义函数三种来源;
  • httpClient:替换默认 HTTP 客户端为 Impit,并以 Firefox 浏览器形态发出页面级请求;
  • maxRequestsPerCrawl: 20:限制本次爬取最多处理 20 个请求,适合快速验证;注释掉则爬取整个站点;
  • browserPool:通过playwrightBrowserPool()工厂显式构建浏览器池,这是接入 Camoufox 的关键。

3. 浏览器池:关闭指纹伪造,注入 Camoufox

browserPool: playwrightBrowserPool({ // Disable the default fingerprint spoofing to avoid conflicts with Camoufox. useFingerprints: false, launchContext: { launcher: firefox, launchOptions: await launchOptions({ headless: false, // Pass your own Camoufox parameters here... // block_images: true, // fonts: ['Times New Roman'], // ... }), }, }),

这里是整个模板的精华:

  • useFingerprints: false:Crawlee 的浏览器池默认会为浏览器生成并注入随机指纹(见 docs/guides/avoid_blocking.mdx 中 "Using browser fingerprints" 一节),但 Camoufox 本身就是一套完整的隐身指纹方案,若再叠加 Crawlee 的指纹伪造反而会互相冲突。因此模板显式关闭默认指纹注入,把伪装工作完全交给 Camoufox;
  • launcher: firefox:指定使用 Playwright 的 Firefox 启动器;
  • await launchOptions({ headless: false, ... })camoufox-jslaunchOptions()会返回 Camoufox 专属参数,这里配置为有头模式headless: false),这也是模板 README 强调"生产就绪"的体现——有头模式配合 Camoufox 的隐身能力更容易通过反爬检测。注释中展示了可传入的 Camoufox 参数,例如block_images: true(屏蔽图片加速加载)、fonts: ['Times New Roman'](指定字体集),更多参数可参考camoufox-js包文档。

playwrightBrowserPool工厂函数定义在 packages/playwright-crawler/src/internals/playwright-browser-pool.ts:它接收launchContextheadlessconfiguration及所有标准BrowserPool选项,自动推导出匹配的 Playwright 浏览器插件,免去手动组装插件的工作。从源码注释可以确认:该工厂返回的浏览器池不会被爬虫自动销毁("The returned pool isnottorn down by the crawler"),因此可以在多个爬虫之间共享同一个池。

4. 启动爬取

await crawler.run(startUrls);

crawler.run(startUrls)会依次完成:清空/初始化存储、构建请求队列并压入起始 URL、按并发策略启动抓取循环、最后等待所有请求处理完毕并持久化结果。

路由文件 routes.ts:链接入队与数据抽取

模板把请求处理逻辑抽到 src/routes.ts,使用 Crawlee 的createPlaywrightRouter()创建路由对象:

import { createPlaywrightRouter } from 'crawlee'; export const router = createPlaywrightRouter(); router.addDefaultHandler(async ({ enqueueLinks, log }) => { log.info(`enqueueing new URLs`); await enqueueLinks({ include: ['https://crawlee.dev/**'], label: 'detail', }); }); router.addHandler('detail', async ({ request, page, log, pushData }) => { const title = await page.title(); log.info(`${title}`, { url: request.loadedUrl }); await pushData({ url: request.loadedUrl, title, }); });
  • addDefaultHandler:默认处理器对所有未匹配路由的请求生效。这里用enqueueLinks({ include, label })从当前页面抽取符合https://crawlee.dev/**的链接入队,并打上detail标签;label是 Crawlee 路由的核心机制,用于把不同页面的处理逻辑路由到不同 handler;
  • addHandler('detail', ...):标签为detail的请求进入此处理器,通过page.title()取标题、request.loadedUrl记录实际加载 URL,最后pushData(){ url, title }写入默认数据集(Dataset);
  • 日志通过log.info输出,loadedUrl是请求最终加载的真实地址(可能存在重定向)。

这套"默认入队 + 标签分发 + pushData 落库"的模式是 Crawlee 爬虫的标准骨架,无论后续要抓取列表页、详情页还是多级链接,都可以在此基础上扩展。

package.json:依赖与构建脚本

模板的 package.json 定义了完整的工程化脚本:

{ "name": "crawlee-camoufox-ts", "version": "0.0.1", "private": true, "type": "module", "dependencies": { "@crawlee/impit-client": "^3.0.0", "camoufox-js": "^0.11.0", "crawlee": "^3.0.0", "playwright": "1.60.0" }, "devDependencies": { "@apify/tsconfig": "^0.2.0", "@types/node": "^24.0.0", "fs-extra": "^11.3.0", "tsx": "^4.4.0", "typescript": "~6.0.0" }, "scripts": { "start": "npm run start:dev", "start:prod": "node dist/main.js", "start:dev": "tsx src/main.ts", "build": "tsc", "get-binaries": "camoufox-js fetch", "postinstall": "npm run get-binaries" } }

关键点:

  • type: "module":项目以 ESM 运行,这也是main.ts中导入./routes.js而非./routes.ts的原因;
  • camoufox-js fetchget-binaries:负责下载 Camoufox 浏览器二进制文件;它被挂到postinstall,即npm install后自动执行,保证首次安装即可运行;
  • start:dev:用tsx直接运行 TS 源码,无需先编译;
  • start:prod:运行tsc编译后的dist/main.js
  • 版本说明:crawlee为 3.x,playwright固定在 1.60.0(与 Dockerfile 基础镜像的 Playwright 版本对应),camoufox-js为 0.11.x。

tsconfig.json:NodeNext 模块策略

tsconfig.json 继承@apify/tsconfig,并显式声明:

{ "extends": "@apify/tsconfig", "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "target": "ES2022", "outDir": "dist", "noUnusedLocals": false, "lib": ["DOM"] }, "include": ["./src/**/*"] }
  • module: "NodeNext"+moduleResolution: "NodeNext":严格按 Node.js ESM 语义解析模块,与type: "module"配套,因此源码中导入必须带.js扩展名;
  • target: "ES2022":编译目标为现代 ECMAScript;
  • lib: ["DOM"]:包含 DOM 类型声明,便于在路由 handler 中安全使用pagedocument等浏览器 API;
  • outDir: "dist":编译产物输出到dist,供start:prod使用。

Dockerfile:Camoufox 专用镜像的多阶段构建

模板提供开箱即用的容器化方案,Dockerfile 采用多阶段构建:

  1. 构建阶段:基于apify/actor-node-playwright-camoufox:24-1.60.0镜像(已预装 Node 24 与 Playwright 1.60.0 对应的 Camoufox 环境),先只拷贝package*.json并执行npm install --include=dev(利用 Docker 层缓存加速),再拷贝全部源码并npm run build编译;
  2. 运行阶段:同样基于 camoufox 基础镜像,仅从构建阶段拷贝dist产物与package*.json,执行npm install --omit=dev安装生产依赖(保持镜像最小化),最后以npm run start:prod启动。

这种"构建镜像装全量依赖、运行镜像只装生产依赖 + 编译产物"的模式,能显著缩小最终镜像体积,同时因为基础镜像自带 Camoufox 二进制,容器内无需再执行camoufox-js fetch

进阶:与防屏蔽方案组合使用

模板是防屏蔽的起点,Crawlee 官方指南 avoid_blocking.mdx 给出了更完整的组合示例(见配套代码 avoid_blocking_camoufox.ts):

import { PlaywrightCrawler, handleCloudflareChallengeHook, playwrightBrowserPool } from 'crawlee'; import { launchOptions } from 'camoufox-js'; import { firefox } from 'playwright'; const crawler = new PlaywrightCrawler({ postNavigationHooks: [handleCloudflareChallengeHook()], browserPool: playwrightBrowserPool({ // Disable the default fingerprint spoofing to avoid conflicts with Camoufox. useFingerprints: false, launchContext: { launcher: firefox, launchOptions: await launchOptions({ headless: true, }), }, }), // ... });

与模板相比,这里多了两个变化:

  • postNavigationHooks: [handleCloudflareChallengeHook()]:页面导航完成后自动检测并处理 Cloudflare 人机挑战,模拟真实用户交互,挑战通过后自动重载页面并把新响应回传爬取上下文;
  • headless: true:可根据场景自由切换有头/无头,模板默认headless: false(更容易通过检测),生产环境按需调整。

此外,防屏蔽指南还解释了浏览器指纹的整体机制:Crawlee 的Session会把 IP、Cookie Jar 与浏览器指纹绑定为一个统一身份,SessionPool整体轮换这些身份。当使用 Camoufox 时,指纹维度已由 Camoufox 接管,因此必须关闭默认指纹注入(useFingerprints: false),避免两套伪装互相冲突——这正是模板这么配置的底层原因。

如何运行模板

packages/templates/templates/camoufox-ts目录下:

npm install # 安装依赖,postinstall 会自动执行 camoufox-js fetch 下载浏览器 npm run start:dev # 以 tsx 直接运行 src/main.ts(有头模式抓取 https://crawlee.dev 前 20 个页面)

运行后,控制台会输出入队与抓取日志,抽取的{ url, title }数据会写入默认数据集(Dataset)。生产部署可直接npm run build && npm run start:prod,或使用仓库内 Dockerfile 构建镜像。

小结

camoufox-ts模板虽然 README 只有寥寥数行,但它的工程实体浓缩了 Crawlee 防屏蔽方案的最佳实践:以PlaywrightCrawler为爬取骨架,通过playwrightBrowserPool显式装配 Firefox + Camoufox,关闭默认指纹注入避免冲突,用 Impit 客户端统一请求层指纹,再配合ProxyConfigurationhandleCloudflareChallengeHook与标签化路由,即可快速搭建一套可对抗主流反爬检测的生产级爬虫。深入阅读 playwright-browser-pool.ts 与 avoid_blocking.mdx 可以进一步理解浏览器池的构建与指纹轮换机制,为扩展自己的反屏蔽策略打下基础。

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

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

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

立即咨询