必须用 puppeteer 在真实环境运行 html 再抓 dom 快照分析,因静态扫描无法发现跨端运行时问题;需设平台 ua/viewport、等业务埋点就绪、对比 page.content() 与渲染后 dom、递归审计 iframe、识别容器篡改痕迹。

怎么用 Puppeteer + Cheerio 做跨端 HTML 动态审计
静态扫描根本发现不了跨端场景下的真实问题——比如 iOS Safari 里被截断的 meta viewport、Android WebView 中因 UA 判断失效导致的降级布局、小程序容器里被劫持的 document.write。必须让 HTML 在真实环境里跑起来,再抓 DOM 快照做分析。
实操建议:
- 用
Puppeteer.launch({ headless: 'new' })启动 Chromium,但别直接用默认 UA;对每个目标平台显式设置userAgent和viewport - 加载页面后,等
networkidle0不够,要加await page.waitForFunction('window.__HTML_AUDIT_READY__')——在业务 JS 末尾手动埋点,确保动态渲染完成 - 用
page.content()拿源码做 Cheerio 静态分析(查标签闭合、SEO 元素),再用page.evaluate(() => document.documentElement.outerHTML)拿渲染后 DOM 做二次比对 - 特别注意
iframe内容:跨端常把核心逻辑塞进沙箱 iframe,得用frame.contentFrame()递归进子上下文审计
为什么 W3C Validator 在跨端审计里会漏报关键问题
W3C 验证器只校验语法合规性,不关心运行时行为。它告诉你 <picture></picture> 标签写法正确,但不会告诉你 Android 4.4 的 WebView 根本不支持 srcset,也不会发现 iOS 15.4 里 display: contents 导致语义化标签丢失。
典型漏报场景:
-
<input type="date">通过验证,但在微信内置浏览器里渲染成普通文本框,且无 fallback 逻辑 -
<meta name="apple-mobile-web-app-capable" content="yes">存在,但manifest.json返回 404,PWA 安装按钮不可见 -
<video preload="metadata"></video>合法,但某些低端安卓机触发canplaythrough事件极慢,造成首屏卡顿
如何识别跨端特有的 DOM 篡改痕迹
很多跨端容器(如飞书、钉钉、企业微信)会在注入 HTML 后主动重写节点:删掉 <script></script>、替换 <a href="https://xxx"></a> 为 openUrl('https://xxx')、给所有 <img> 加上 data-src 属性。这些操作不会报错,但会让原始代码质量指标失效。
检查方法:
- 对比
page.content()和page.evaluate(() => document.documentElement.outerHTML)的 diff,重点看script、iframe、a、img标签是否被增删或属性被改写 - 搜索是否存在全局函数如
dd.ready、lxg.openUrl、ww.openUrl,它们出现的位置往往就是容器注入逻辑的锚点 - 检查
document.body上是否新增了非业务类class(如__wxjs_environment、feishu-bridge),这是容器 SDK 注入的明确信号
移动端 viewport 设置被覆盖的隐蔽问题
业务代码写了 <meta name="viewport" content="width=device-width, initial-scale=1.0">,但跨端容器可能在初始化阶段插入自己的 <meta> 并设为 name="viewport",靠 DOM 插入顺序覆盖原值。浏览器只认第一个,后面全失效。
排查步骤:
- 用
page.evaluate(() => Array.from(document.querySelectorAll('meta[name="viewport"]')).map(m => m.outerHTML))拿到全部 viewport meta - 检查它们的
parentNode是否为document.head,还是被 append 到某个动态创建的<div> 里(说明是 JS 注入) <li>监听 <code>DOMSubtreeModified事件(或用MutationObserver)捕获 meta 节点变动时机,定位篡改脚本 - 注意某些容器(如早期 QQ 浏览器)会强制重写 viewport,连
document.write都拦截不了,只能在beforeunload阶段抢在它前面写
跨端 HTML 审计最难缠的不是语法错误,而是那些“合法但失效”的结构——标签没写错,属性值也合规,只是在特定容器里被静默降级、覆盖或重定向。盯住渲染后 DOM 与原始 HTML 的差值,比盯着 validator 报告有用得多。











