网站识别headless爬虫主要靠运行时环境检测而非ip或频率,如navigator.webdriver为true、window.chrome缺失、navigator.plugins为空等dom层面“非人痕迹”,这些在页面加载早期即触发拦截。

Headless浏览器爬虫被识别,八成不是因为IP或频率,而是HTML结构层面暴露了“非人痕迹”——比如 document.documentElement.outerHTML 里藏着空的 navigator.plugins、window.chrome 缺失、webdriver 属性为 true。这些不是“配置没调好”,是默认行为直接写死在 DOM 和 JS 运行时环境里的。
为什么 document.body.innerHTML 看不出问题,但网站 JS 却能秒判是无头?
因为反爬逻辑不依赖你看到的 HTML 内容,而是读取运行时环境对象。比如一段典型检测脚本会这样写:
if (navigator.webdriver === true || !window.chrome || navigator.plugins.length === 0) { throw 'bot' }
这类判断在页面加载早期就执行,甚至在 DOM 渲染前就已触发重定向或拦截。你用 page.content() 拿到的 HTML 是“结果”,而检测发生在“过程”中。
常见误操作包括:只改 UA、只加延时、只等 networkidle —— 这些对上述 JS 检测完全无效。
- UA 可伪造,但
navigator.permissions.query返回TypeError无法绕过 -
page.evaluate()手动设Object.defineProperty(navigator, 'webdriver', {value: false})仅对当前上下文生效,且可能被后续 JS 覆盖 - Chrome 启动参数如
--disable-blink-features=AutomationControlled必须配合--exclude-switches=enable-automation,漏一个就白配
Playwright vs Selenium 在 DOM 层级加固上的关键差异
Playwright 默认比 Selenium 更难被识别,核心在于它不注入 webdriver 属性、不暴露 cdc_ 开头的 Chrome DevTools 原生函数名,且自动禁用部分自动化指纹特征。
但默认仍不安全:Selenium 的 chromedriver 会在 window 上挂载 cdc_ 变量;Playwright 的 chromium 实例若未显式覆盖 userAgent 和 viewport,仍会返回固定值(如 languages 恒为 ["en-US", "en"])。
- Selenium 必须手动 patch
cdc_变量:用二进制编辑器改chromedriver文件,或启动后执行 JS 注入覆盖(风险高、易失效) - Playwright 推荐用
launch_persistent_context+user_agent+locale+timezone_id组合配置,避免用launch()直接启新实例 - 两者都需禁用
--enable-automation参数(Playwright 默认已禁,Selenium 需显式options.add_experimental_option("excludeSwitches", ["enable-automation"]))
真实用户 DOM 行为特征怎么补?光靠 page.goto() 不够
很多站点会监听 mousemove、scroll、keydown 事件的触发密度和轨迹。纯 goto + wait_for_load_state 产生的页面,performance.getEntriesByType('navigation') 中的 type 字段是 reload 或 back_forward,而非真实用户常见的 navigate —— 这个差异能被前端轻易采集。
- 必须在
goto()后主动触发一次滚动:page.mouse.wheel(0, 200),再等page.wait_for_timeout(500) - 避免使用
page.screenshot()前不触发任何交互 —— 截图本身会触发visibilitychange,但无前置行为会被标记为“静默访问” - 若目标站依赖
document.visibilityState === 'visible'才加载数据,需先page.bring_to_front()(Playwright)或driver.execute_script("window.focus()")(Selenium)
DOM 层面的加固不是“打补丁”,而是重建一套符合真实浏览器生命周期的行为链:从启动参数 → 运行时对象劫持 → 页面导航 → 用户事件注入 → 资源加载等待,每一步都有可被检测的断点。最容易被忽略的是:你 patch 了 navigator.webdriver,但忘了 HTMLMediaElement.prototype.canPlayType.toString() 在无头环境下返回空字符串 —— 这个冷门属性,正被越来越多站点加入检测清单。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











