你按下 F12,页面一片空白。或者它把你弹回首页,或者冻在“Paused in debugger”横幅后面,或者显示“developer tools detected”然后就不再加载。不管是哪一种,网站都发现了,而且没有任何事件通知过它。
页面里的脚本,不会在你打开 DevTools、选中某个元素或查看某个面板时收到任何信号。它们能做的,是察觉打开的 DevTools 给页面带来的影响。本页上的小工具会在你自己的浏览器上运行这些检测,所以现在就打开 DevTools,看看它怎么反应。
debugger 语句会让页面停住,而时钟照常走。这三种里有两种有简单的绕过办法(取消停靠面板,停用断点)。控制台计时则没有这样的办法,而且连 Puppeteer 也会触发它。这些检测都不会识别出具体的人,小工具里的检查完全在你的浏览器中运行。网站能看到你使用“检查元素”吗?
通过脚本看不到。浏览器不会触发“DevTools 已打开”事件,选中元素或查看面板也不会告诉页面任何事。服务器仍然看得到普通请求。查看源代码就是对页面发起的一次普通请求,或者从缓存里读一份。DevTools 打开时 Chrome 还会去取网站的 source map,所以提供 source map 的服务器可以把这一点记下来。但它永远不知道你选中了哪个元素,也不知道你在看哪个面板。
在“检查元素”里改页面,不会影响其他任何人。你改的是你标签页里的那份副本,服务器上的副本纹丝不动,重新加载就会恢复原样。页面可以察觉到自己的某个元素被改动了,因为 MutationObserver 会把这类修改当作普通的 DOM 变化上报。我在 Chrome 中确认了文本和属性的修改都会被上报,而且这条记录并不说明是谁改的。在小工具里拿价格试一试:右键点它,选择“检查”,然后编辑文字。下图展示了这个改动落在哪里。
页面是怎么知道 DevTools 已打开的
其中三种手法的原理相同。页面没法直接问“DevTools 开了吗?”,所以它先设置一项测量,再观察有没有副作用。思路和广告拦截器检测一样:页面看不到这个工具,就去测量这个工具改变了什么。
窗口尺寸差值。 把 DevTools 停靠在侧边或底部,会占掉页面的一部分空间,于是 window.outerWidth - window.innerWidth(或者高度的对应值)会猛增。脚本会把大约 160 到 170 像素的差值判定为命中。在我的 Windows 11 电脑上,把 DevTools 停靠到右侧,宽度差值从 14 像素变成了 569 像素,取消停靠后又回到 14。你缩放页面或者打开侧边栏时,它会误报。最有名的相关库 devtools-detect 在 2026 年 5 月被归档了,它的 README 也承认这种方法误报很多。
控制台开销。 经典的把戏是记录一个带 getter 的对象,然后看控制台会不会去读它。很多老答案至今还在这么讲,但它在当前的 Chrome 里已经不再触发:我在 Windows 版 Chrome 155 上测试,DevTools 打开时,挂在 Error.stack 上的 getter 和挂在元素 id 上的 getter 都没有响。其他变种,比如自定义 toString,无论 DevTools 开不开都会触发,所以什么也说明不了。
仍然能看出来的是时间。在没有控制台客户端连接之前,输出日志几乎不花时间,一旦连上,Chrome 就得为每个对象生成预览。对一个有 40 个键的对象调用 40 次 console.debug,DevTools 关闭时耗时不到一毫秒,打开后要几毫秒,在我的电脑上大约是十倍的跳升。面板是停靠还是在独立窗口里,结果没有区别。只用一个裸的 Chrome DevTools Protocol 会话,也出现了同样的跳升,而这正是 Puppeteer 和 Playwright 默认打开的东西。页面只要拿自己输出日志的耗时去对比基线,就能看出来。它也分不清开发者和脚本,这正是机器人检测会用到它的原因。我没有测试过 Firefox 和 Safari。
debugger 语句。 没有 DevTools 时,它什么也不做。DevTools 打开且断点启用时,它会让页面停住,直到你按下“继续执行脚本”(F8)。脚本在前后各读一次时钟,间隔超过约 100 ms 就当作发生了暂停。脚本由此推断有人在看,不过被节流的标签页或者慢吞吞的机器也能伪造出这种间隔。“Paused in debugger”横幅就是这么来的。小工具里的按钮会运行它一次,让你亲身感受一下。
编辑监视器。 第四个信号根本不是 DevTools 检测。它就是上一节提到的 MutationObserver,指向脚本想保护的任何东西,比如价格或付费墙元素。它上报的是改动,而不是 DevTools。
- 抓到窗口尺寸差值外层窗口减去页面区域
- 抓到控制台开销拿 40 次控制台调用的耗时与基线对比
- 抓到debugger 计时一条 debugger 语句加一块秒表
网站为什么会冻结、重定向或提示“developer tools detected”
会做出反应的网站,用的不是单一的把戏。Christian Heilmann 曾在 Cracking a “Developer Tools Killer” script 里拆解过一个。它会拦截右键,以及 F12、Ctrl+Shift+I 和 Ctrl+U 这几个快捷键,然后每 100 ms 跑一轮 debugger 循环,一旦某次暂停超过 200 ms 就重定向页面。它的检查函数没有包在闭包里,所以他直接把它覆盖掉了。
动机通常是让复制和抓取更麻烦一点。它什么也保护不了,因为服务器发来的所有内容本来就已经在你的浏览器里。复制、粘贴、切换标签页和截图是另一组信号,请看网站能看到你切屏、复制或截图吗。
网站能禁用“检查元素”或 F12 吗?
页面可以取消 F12 和 Ctrl+Shift+I 的按键事件,也可以取消右键菜单,大多数“禁用”脚本做的就是这些。这只是表面功夫。浏览器菜单(更多工具 > 开发者工具)在页面之外运行,页面拦不住。小工具的最后一行会记录这些事件里有哪些在你的浏览器中到达了页面。它只旁观,从不取消它们。
如何绕过 DevTools 检测、解除页面冻结
DevTools 是浏览器的标准功能,所以被它触发的检测是网站自己的问题。针对不同的检测,对症下药:
- 停用断点:在“来源”(Sources)面板里操作(Ctrl+F8,Mac 上是 Cmd+F8)。每条
debugger语句都会变成空操作,暂停检测就看不到间隔了。 - 取消停靠面板,让它变成独立窗口,这样就能绕过窗口尺寸差值的检测。
- 如果触发的是控制台计时,就得直接处理脚本本身。没有任何设置能让页面看不到控制台。你可以覆盖或屏蔽检测脚本,就像 Heilmann 的拆解里覆盖它的检查函数那样,或者去查看一份保存下来的、不会运行任何脚本的页面副本。
不要去用那种伪造 window.outerWidth 或者给 console 打补丁的扩展。被替换掉的内置函数不再报告 [native code],这本身就是一个破绽,就像机器人检测中的被打过补丁的原生函数一样。
使用“检查元素”违法吗?
不违法。每个主流浏览器都内置并且公开记录了它,而且它只会编辑你本地的副本。麻烦出在你接下来做什么:把一张篡改过的截图冒充成真实的收据、发票或银行对账单,视你所在的地方和你的意图而定,可能构成伪造或欺诈,不管是用哪个工具做的。
如果你大规模运行浏览器
对开发者来说,触发检测意味着页面坏掉,直到你停用断点为止。对大规模运行浏览器的人来说,这意味着每个给控制台计时的网站上都会被打上标记,因为自动化通道一接入,开销就会变,不只是真人打开 DevTools 的时候才变。如果你用 Puppeteer 或 Playwright 驱动配置文件,在依赖它之前,先拿每一种配置在上面的小工具里跑一遍,而且不要打开任何 DevTools 窗口。
Incogniton 的配置文件是真正的 Chromium 构建,所以上面的检测对它们和对 Chrome 一样适用。控制台计时是否保持安静,取决于你怎样驱动配置文件,这一部分请自己测试。某个网站是否允许自动化,由它自己的规则决定,所以先读一读。现在就试试:在小工具的监视下打开 DevTools,然后取消停靠面板,再停用断点。有两行会安静下来,控制台那一行不会。完整的浏览器扫描涵盖了页面还能读到的其余内容,从网络到指纹。