基于 puppeteer-extra-plugin-stealth 的 `_template` 模板开发自定义反检测插件实战指南
网页爬虫浏览器控制测试【免费下载链接】puppeteer-extra Teach puppeteer new tricks through plugins.项目地址https://gitcode.com/gh_mirrors/pu/puppeteer-extra点击查看免费下载本文以 packages/puppeteer-extra-plugin-stealth/evasions/_template 目录下的官方模板为起点讲解如何在 puppeteer-extra 体系中从零编写一个可独立运行的反检测 evasion 插件。读完本文你将掌握最小插件骨架的每一行代码、PuppeteerExtraPlugin基类的生命周期钩子、共享工具库_utils的正确用法并能参照navigator.webdriver、chrome.app等真实 evasion 的实现快速复制模板目录并开发出自己的新反检测方案。模板的本质一个最小的反检测插件骨架_template是puppeteer-extra-plugin-stealth官方提供的最小可运行插件模板官方对其定位非常直白见 模板 readmeMinimal stealth plugin template, not being used. :-) Feel free to copy this folder as the basis for additional detection evasion plugins.翻译过来就是这个模板本身并不参与实际反检测not being used它的用途是作为复制即用的起点——当你发现一个新的 headless 可探测特征、想为 stealth 插件贡献一条新 evasion 时直接复制整个_template文件夹改一改类名、插件名和onPageCreated里的注入逻辑即可。这也是 stealth 主插件官方建议的贡献路径主插件 index.js 的注释明确写着if you want to add a new evasion technique I suggest you look at the template to kickstart things。一个完整的 evasion 插件目录由三部分构成文件作用index.js插件本体继承PuppeteerExtraPlugin并实现生命周期钩子readme.md由documentation.js自动生成的 API 文档npm run docs会更新它package.json声明main: index.js与private: true见 模板 package.json目录结构可参照真实的navigator.pluginsevasionnavigator.plugins 目录除了index.js还按需附带mimeTypes.js、plugins.js、magicArray.js、data.json等拆分文件与配套测试。模板源码逐行拆解模板的完整实现位于 evasions/_template/index.js全文件仅 28 行结构如下use strict const { PuppeteerExtraPlugin } require(puppeteer-extra-plugin) /** * Minimal stealth plugin template, not being used. :-) * * Feel free to copy this folder as the basis for additional detection evasion plugins. */ class Plugin extends PuppeteerExtraPlugin { constructor(opts {}) { super(opts) } get name() { return stealth/evasions/_template } async onPageCreated(page) { await page.evaluateOnNewDocument(() { console.debug(hello world) }) } } module.exports function(pluginConfig) { return new Plugin(pluginConfig) }第一行严格模式use strict是 stealth 插件家族所有实现navigator.webdriver、chrome.app、navigator.plugins等的统一开头。由于这些代码最终会通过page.evaluateOnNewDocument注入浏览器页面上下文保持严格模式能避免一些隐蔽的静默错误。类的骨架与 opts 传递class Plugin extends PuppeteerExtraPlugin { constructor(opts {}) { super(opts) }PuppeteerExtraPlugin来自独立包puppeteer-extra-pluginstealth 的依赖声明见 package.json。它的构造函数会做一件关键的事把插件定义的defaults与用户传入的opts做深合并合并结果保存在this.opts中插件运行期通过this.opts.xxx读取配置见 src/index.ts 的_opts merge(this.defaults, opts || {})。name插件的全局唯一标识get name() { return stealth/evasions/_template }name是PuppeteerExtraPlugin基类要求每个插件必须覆写的属性基类默认实现会直接抛错Plugin must override name见 src/index.ts。它同时承担三个职责调试命名空间this.debug()的日志会以puppeteer-extra-plugin:${name}为前缀输出可用DEBUGpuppeteer-extra-plugin:插件名环境变量开关见 src/index.ts依赖解析stealth 主插件通过dependenciesgetter 把启用列表映射为stealth/evasions/名字形式的依赖名见 stealth index.jspuppeteer-extra会自动require()缺失的依赖见 src/index.ts事件绑定去重基类用_hasChildClassMember检查子类是否真的实现了某个钩子再决定是否注册对应的事件监听见 src/index.ts。命名惯例上真实 evasion 采用stealth/evasions/目录名格式例如stealth/evasions/navigator.webdriver、stealth/evasions/chrome.app。复制模板后第一件事就是把这里改成你的新 evasion 名称。onPageCreated反检测逻辑的注入点async onPageCreated(page) { await page.evaluateOnNewDocument(() { console.debug(hello world) }) }这是模板的灵魂所在。onPageCreated是基类提供的生命周期钩子之一当浏览器创建新页面包括window.open、browser.newPage、隐身上下文中的页面时被调用且已由基类预先过滤为page类型 target见 src/index.ts。基类通过监听 puppeteer 的targetcreated事件触发它。page.evaluateOnNewDocument保证注入脚本在页面任何脚本执行之前运行——这正是 stealth 反检测先下手为强的关键在页面自身的检测代码运行前先把navigator.webdriver、window.chrome等特征改写掉。真实插件对这一点利用得淋漓尽致例如navigator.webdriver/index.js 在onPageCreated中根据 Chrome 版本删除原型上的webdriver属性chrome.app/index.js 在 headless 下完整 mockwindow.chrome.appwindow.outerdimensions/index.js 补上 headless 缺失的window.outerWidth/outerHeight。模块导出工厂函数模式module.exports function(pluginConfig) { return new Plugin(pluginConfig) }模板采用工厂函数而不是直接导出类实例这是 stealth 插件家族的统一约定所有 evasion 的index.js末尾都是这个模式。这样做的原因在于opts的延迟注入调用方写成require(...)({ userAgent: ... })参数在实例化时才传入并参与defaults合并。默认参数opts {}在构造函数签名中已给出文档中标注opts (optional, default{})确保无参调用也能工作。生命周期钩子一个 evasion 能用到哪些时机PuppeteerExtraPlugin基类为插件提供了完整的一套钩子覆盖浏览器从启动到关闭的全过程全部为可选实现见 src/index.ts钩子触发时机典型用途beforeLaunch(options)新浏览器启动前修改 puppeteer 启动参数如追加--disable-blink-featuresAutomationControlledafterLaunch(browser, opts)浏览器启动后获取浏览器实例引用beforeConnect(options)puppeteer.connect()前修改连接参数afterConnect(browser, opts)连接建立后处理已连接浏览器onBrowser(browser, opts)launch/connect 任一方式拿到浏览器时统一处理两种来源onTargetCreated(target)新 target 创建处理任意类型 targetonPageCreated(page)新页面创建注入反检测脚本模板核心onTargetChanged(target)/onTargetDestroyed(target)target 变化/销毁状态清理onDisconnected()与浏览器断开清理资源onPluginRegistered()puppeteer.use()注册后初始化配套还有三个配置类 getter见 src/index.tsdefaults插件默认配置与用户 opts 深合并requirements声明launch不支持 connect、headful不支持 headless、dataFromPlugins、runLast等需求供基类向用户告警或调整执行顺序dependencies声明依赖的其他插件缺失时由puppeteer-extra自动加载。模板只用了onPageCreated这一个钩子但真实 evasion 常常组合多个。最典型的例子是 user-agent-override/index.js它同时实现了onPageCreated通过 CDP 的Network.setUserAgentOverride设置 UA 与平台、beforeLaunch记录是否 headless、beforeConnect把 connect 方式视为 headless以及data向user-preferences插件提供语言偏好数据还声明了dependencies: new Set([user-preferences])。使用共享工具库_utils让 mock 不留痕迹模板为了保持最小直接用了裸page.evaluateOnNewDocument。但 stealth 家族约 16 个 evasion完整清单见 stealth/index.js 的availableEvasions中大部分改写在技术上有一个共性痛点直接Object.defineProperty或new Proxy会留下可被反检测的蛛丝马迹例如Proxy 会出现在错误堆栈里at Reflect.get、at Object.get等行被替换函数的toString()结果不再是function xxx() { [native code] }新增属性会出现在Object.getOwnPropertyNames枚举中。puppeteer-extra-plugin-stealth/evasions/_utils目录正是为消除这些痕迹而生的共享工具箱_utils/index.js核心工具函数集合包括stripProxyFromErrors剥离 Proxy 错误堆栈、replaceProperty基于原有 descriptor 安全替换属性、patchToString/redirectToString伪造原生toString结果、replaceWithProxy/replaceGetterWithProxy/replaceGetterSetter/mockWithProxy/createProxy带反检测的 Proxy 包装、preloadCache/makeNativeString缓存原生toString字符串以防被二次嗅探、stringifyFns/materializeFns函数在 Node 与浏览器上下文间传递、memoize等_utils/withUtils.js对 page 的轻量封装提供page.evaluate和page.evaluateOnNewDocument的带工具版把_utils里的函数序列化后注入页面上下文页面内通过utils参数直接调用。一个使用withUtils的典型实现是 chrome.app/index.jsasync onPageCreated(page) { await withUtils(page).evaluateOnNewDocument(utils { // headless 下 window.chrome 不存在按 headful 的真实 descriptor 定义 Object.defineProperty(window, chrome, { writable: true, enumerable: true, configurable: false, value: {} }) // ... 构造 chrome.app 的静态数据与方法 mock utils.patchToStringNested(window.chrome.app) // 让所有 mock 函数看起来是原生代码 }) }navigator.pluginsevasionnavigator.plugins/index.js则展示了函数与数据分离的进阶写法把generateMimeTypeArray、generatePluginArray等生成函数用utils.stringifyFns序列化后随data来自data.json一起作为evaluateOnNewDocument的参数传入页面内再用utils.materializeFns还原——既保持了代码结构清晰又绕过了page.evaluate无法直接传函数的序列化限制。开发建议如果你的新 evasion 需要改写原生 API而不是像模板那样仅仅打印日志请务必复制_template后改用withUtils(page).evaluateOnNewDocument(...)模式并复用_utils中已有的工具避免能用但会被检测出来的半成品实现。实战如何把模板变成你自己的 evasion参照官方在 evasions/readme.md 中给出的指引If you want to add a new evasion technique I suggest you look at the template to kickstart things完整开发流程如下第 1 步复制模板目录把_template整个复制为evasions/你的新名字并同步修改package.json与readme.md。第 2 步改写插件名get name() { return stealth/evasions/你的新名字 }第 3 步实现反检测逻辑在onPageCreated中实现你的检测点修复。逻辑分两种形态直接修补类适合简单场景如 navigator.webdriver/index.jsasync onPageCreated(page) { await page.evaluateOnNewDocument(() { if (navigator.webdriver false) { // Post Chrome 89.0.4339.0 and already good } else if (navigator.webdriver undefined) { // Pre Chrome 89.0.4339.0 and already good } else { // Pre Chrome 88.0.4291.0 and needs patching delete Object.getPrototypeOf(navigator).webdriver } }) }该插件还在beforeLaunch中向启动参数追加--disable-blink-featuresAutomationControllednavigator.webdriver/index.js并注释了 Linux 下去掉 Chrome 警告 infobar 的 Chrome 策略配置方法。工具库辅助类适合 Proxy mock 场景如 media.codecs/index.js用utils.replaceWithProxy(HTMLMediaElement.prototype, canPlayType, canPlayType)拦截canPlayType调用对 Chromium 缺失的video/mp4; codecsavc1.42E01E、audio/x-m4a、audio/aac返回probably/maybe。第 4 步编写测试强烈建议stealth 插件的测试体系由 ava 驱动测试脚本见 package.json并提供了一组指纹采集工具 test/util.jsgetVanillaFingerPrint用原生 puppeteer 采集指纹、getStealthFingerPrint用addExtra(vanillaPuppeteer).use(Plugin())采集加了你的 evasion 之后的指纹两者对比即可验证效果。典型写法可参考 navigator.webdriver/index.test.js先断言 vanilla 下navigator.webdriver true再断言 stealth 下等于falseChrome ≥ 89.0.4339.0或undefined更早版本并附带回归测试确认不会误伤其他navigator方法。第 5 步独立使用或并入 stealth 主插件新 evasion 本身就是一个标准的puppeteer-extra插件可以独立使用const puppeteer require(puppeteer-extra) puppeteer.use(require(puppeteer-extra-plugin-stealth/evasions/你的新名字)())如果想并入 stealth 全家桶则需要两步见 stealth/index.js把新名字加入defaults中的availableEvasionsSet第 82-99 行enabledEvasions默认复制全部可用项第 103 行这样dependencies就会自动生成对应的依赖名并由puppeteer-extra动态加载第 112-116 行。常见问题与注意事项不要用page.setUserAgent()与 stealth 的 UA 处理混用user-agent-override插件注释明确警告常规的page.setUserAgent()会重置插件设置的语言与平台值见 user-agent-override/index.js。同理开发新 evasion 时要意识到 stealth 各插件之间是协同关系避免互相覆盖。evaluateOnNewDocument里不能直接用 Node 侧闭包变量需要通过withUtils的参数机制或stringifyFns序列化传递这是_utils存在的重要原因。保持模块化与最小依赖stealth 主插件的设计哲学是只加载启用的 evasion见 stealth/index.js 的 Modularity 说明。你的新插件应尽量自包含必要时才声明dependencies。documentation.js注释驱动文档readme.md由npm run docs内部执行documentation readme --shallow见 package.json从index.js的 JSDoc 注释自动生成。给类和方法写规范的 JSDocreadme.md的 API 段才会完整。版本与场景边界本仓库puppeteer-extra-plugin-stealth版本为 2.11.2引擎要求 Node 8见 package.json各 evasion 的实现细节如navigator.webdriver对不同 Chrome 版本的分支处理以源码注释为准实际效果随 Chrome 版本演进可能变化。总结_template虽只有 28 行代码却完整定义了 stealth evasion 插件的标准形态继承PuppeteerExtraPlugin、覆写name、在onPageCreated中通过evaluateOnNewDocument抢先注入补丁、以工厂函数导出。从它出发你可以对照_utils工具箱与navigator.webdriver、chrome.app、navigator.plugins、media.codecs等真实实现快速产出一个既模块化、又经得起指纹检测对比测试的新反检测插件——这正是 puppeteer-extra 社区持续扩展 stealth 能力的标准路径。赞分享网页爬虫浏览器控制测试【免费下载链接】puppeteer-extra Teach puppeteer new tricks through plugins.项目地址https://gitcode.com/gh_mirrors/pu/puppeteer-extra点击查看免费下载相关推荐puppeteer-extra-plugin-stealth 反检测插件解析navigator.hardwareConcurrency 硬件并发数伪装原理与实战puppeteer extra plugin stealth 反检测插件解析navigator.hardwareConcurrency 硬件并发数伪装原理与实网页爬虫浏览器控制测试puppeteer-extra-plugin-stealth 的 navigator.permissions 反检测插件原理、源码与测试全解析puppeteer extra plugin stealth 的 navigator.permissions 反检测插件原理、源码与测试全解析 在 puppe网页爬虫浏览器控制测试puppeteer-extra 插件解析chrome.loadTimes 反检测插件原理与实战puppeteer extra 插件解析chrome.loadTimes 反检测插件原理与实战 chrome.loadTimes 是 Chrome 专属的浏览网页爬虫浏览器控制测试创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2020-2021中国开发者调查报告:数据挖掘与工程化分析实践

2020-2021中国开发者调查报告:数据挖掘与工程化分析实践

简介:《2020-2021中国开发者调查报告》由CSDN官方出品,面向IT行业决策者、市场研究人员及广大开发者,系统呈现中国开发者群体的技术行为与行业趋势。报告基于CSDN自2004年积累的开发者调查数据,结合年度问卷重新设计,并…

2026/10/15 22:15:49 阅读更多 →
GoAnime 移动端与社区生态全解析:Android 版 + Discord 社区怎么加入

GoAnime 移动端与社区生态全解析:Android 版 + Discord 社区怎么加入

【免费下载链接】GoAnime Search, stream and download anime, movies and TV shows from the terminal, in English and Brazilian Portuguese. 项目地址: https://gitcode.com/gh_mirrors/go/GoAnime 点击查看 免费下载 GoAnime 是一款基于 Go 语言、运行在终端里…

2026/10/15 22:15:49 阅读更多 →
自建S3兼容对象存储实战:从部署到避坑

自建S3兼容对象存储实战:从部署到避坑

自建S3兼容对象存储这事儿,最近几年越来越多人问。公有云的对象存储接口确实好用,但很多场景——比如数据完全不能出内网、项目要离线交付、又或者就是单纯想省掉按量计费的账单——都想在自家服务器上搞一套同样的接口服务。我自己前后搭了好几套&#…

2026/10/15 22:14:47 阅读更多 →

最新新闻

Claude Code + DeepSeek 从零安装教程:面向纯小白,6 步拥有自己的 AI 编程助手|TaoToken 统一 Key 接入

Claude Code + DeepSeek 从零安装教程:面向纯小白,6 步拥有自己的 AI 编程助手|TaoToken 统一 Key 接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:56:22 阅读更多 →
LOAM前端scanRegistration深度拆解:去畸变、曲率计算与特征提取调参实战

LOAM前端scanRegistration深度拆解:去畸变、曲率计算与特征提取调参实战

1. 从一次调试翻车说起:scanRegistration到底在干什么去年冬天调一个室外建图项目,前端里程计跑着跑着轨迹突然炸开,rviz里点云像天女散花一样乱飞。排查了两天,最后定位到scanRegistration节点输出的曲率计算有问题——边缘点和平…

2026/10/15 22:56:22 阅读更多 →
我的开源项目:把退货原因整理成可核对的商品改进清单

我的开源项目:把退货原因整理成可核对的商品改进清单

我的开源项目:把退货原因整理成可核对的商品改进清单 这是我的100个开源项目系列,介绍 shop-returns-reason-summary-cn。它是一份供 AI 助手使用的 Markdown Skill,按明确规则整理使用者提供的脱敏退款/退货记录。项目没有售后后台连接器&a…

2026/10/15 22:56:22 阅读更多 →
MyBatis Generator XML配置实战:从模板到代码生成全解析

MyBatis Generator XML配置实战:从模板到代码生成全解析

从 MyBatis Generator 的 XML 配置看起,很多人第一次用这个工具时对着配置模板一头雾水:classPathEntry是什么意思?table里的domainObjectName到底要不要写全限定名?targetProject该填什么路径?我又不希望生成Example类…

2026/10/15 22:56:22 阅读更多 →
Java学生成绩管理系统实战:从解压到二次开发全指南

Java学生成绩管理系统实战:从解压到二次开发全指南

简介:这是一套面向Java初学者与课程设计学习者的学生成绩管理系统完整源码,基于Java语言开发,搭配MySQL数据库,适合用于课程设计参考、毕业设计练手或Java GUI与JDBC实战学习。压缩包共104个文件,约714KB,包…

2026/10/15 22:56:22 阅读更多 →
喂文件、写代码、聊天:三个开源工具打造本地化AI工作流

喂文件、写代码、聊天:三个开源工具打造本地化AI工作流

1. 项目概述:为什么“喂文件、写代码、聊天”这三件事,才是AI真正落地的临界点最近在几个技术社区和产品团队内部做AI工具链调研时,反复听到一句话:“模型能力早就够了,卡在怎么用上。”不是模型不够聪明,而…

2026/10/15 22:55:22 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →