html结构混淆对基础爬虫有效,因为requests+beautifulsoup等工具仅解析静态html,无法执行js或计算css,当关键文本被拆解、错位或包裹在无意义标签中时便无法提取;但对puppeteer等浏览器驱动爬虫基本无效。

HTML结构混淆为什么对基础爬虫有效
因为大多数简单爬虫(比如用 requests + BeautifulSoup 的脚本)只做静态 HTML 解析,不执行 JS、不计算 CSS、不处理 DOM 动态变化。只要关键文本不出现在原始 HTML 字符串里,或被拆解/错位/包裹在无意义标签中,它们就抓不到完整字段。
但注意:这层防护对 Puppeteer、Playwright 等真实浏览器驱动的爬虫基本无效——它们能等 JS 执行完再取 DOM,和用户看到的一样。
- 混淆目标不是“彻底防住”,而是提高批量采集成本,筛掉 80% 的低门槛盗取行为
- 混淆后源码体积会增大,可能影响首屏解析速度,需权衡
- 过度嵌套或非法嵌套(如
<div><p><span><a></a></span></p></div>套五层)可能触发某些解析器异常,反而导致漏抓
用 CSS 伪元素拼接文本的实操要点
把一个价格“¥299”拆成三部分,分别塞进 ::before 和 ::after 伪元素,主 HTML 里只剩空容器。这样 bs4.find("span") 拿到的是空标签,正则也匹配不到完整数字。
示例:
<span class="price" data-val="299"></span>
CSS 中写:
.price::before { content: "¥"; }
.price::after { content: attr(data-val); }
- 必须用
attr()引用属性值,不能直接写死内容(否则仍暴露在 HTML 中) - 不要依赖
getComputedStyle(el).content—— 真爬虫可调用它还原,仅防静态解析 - 移动端 Safari 对
attr()支持良好,但 IE11 及更早版本不支持,若需兼容需降级 fallback
JS 动态注入 HTML 的常见陷阱
很多人用 document.write() 或 innerHTML 拼接关键文案,但没意识到:这些字符串依然存在于 JS 源码里,grep -r "订单号" *.js 就能扫出来。
- 避免明文字符串:
el.innerHTML = "订单号:" + order.id→ 明文“订单号:”仍可被正则提取 - 改用数组打乱 + 拼接:
const t = ["号","单","订",":"]; el.textContent = t.reverse().join(''); - 敏感字段优先走 API 请求,而不是前端 JS 拼接;哪怕只是 fetch 一次,也能把原始数据留在服务端校验逻辑里
- 如果必须前端渲染,把字符串拆成 Unicode 编码(如
"\u5b9e"\u9645"),但注意粘贴到输入框时可能变成乱码
结构干扰:无语义标签与冗余嵌套的实际效果
在关键节点外层加多层 <span><div>
<i><b> 包裹,并给它们设 <code>display: contents 或 font-size: 0,目的是让 XPath 或 CSS 选择器失效——原本 div.product > p.price 变成需要定位中间七八个无关节点。
- 别用
display: none或visibility: hidden—— 这类元素会被主流解析器默认忽略,反而更易过滤 - 用
opacity: 0.01或position: absolute; left: -9999px更稳妥,元素仍在 DOM 树中 - 每个干扰层加随机 class 名(如
zq8x2),并配合服务端每次响应生成不同 class,防 selector 固定规则匹配 - 注意:DOM 节点过多会拖慢 JS 渲染性能,尤其低端安卓机上明显卡顿
真正难绕过的永远是服务端逻辑——混淆只是把“能不能拿到”变成“值不值得花半小时写新解析器”。一旦对方决定投入人力逆向,HTML 层面所有手段都只是延缓时间而已。











