偶遇 HTML 中的奇妙字符


虽然名字听起来就像是一本正经的胡说八道,但吾辈确实遇到了一个奇怪的问题,于此分享给大家。

事情的起始如下

下班回家 => 想要看动画 => 去动漫花园下载 BT 种子 => 动漫花园一片空白 => Why?

默认 uBlock 屏蔽页面

于是吾辈偷偷的的打开了控制台看了一下,发现是页面中的内容元素不见了。经过深思熟虑(好吧其实也就是稍微想了一下)首先把 uBlock 禁用,毕竟这个最容易被网站检测出来并且对抗嘛!果不其然,页面恢复了正常,但。。。同时广告也出现在了页面上。

默认 uBlock 不屏蔽页面

这可不行,重新启用了 uBlock 看了一下分析,很显然,内容不存在大概率是被 uBlock 的元素过滤功能隐藏掉了,查看被隐藏的内容元素,发现 id 为 1280_adv,但同时又包含了广告与主体内容,所以只要关掉 uBlock 的元素过滤就可以避免正常内容被误杀了。

之所以不在该网站整个禁用掉 uBlock 的原因在于 uBlock 并不只有元素过滤,它还阻止了一些广告资源的加载,仅在动漫花园就包括但不限于 _baidu.com, bebi.com, histats.com_。显而易见,禁用它们还能提高加载速度。

uBlock 屏蔽的脚本

既然无法使用 uBlock 的元素屏蔽了,那么吾辈便需要使用一个新的方式去阻止广告了,幸运的是吾辈安装了 Stylus 和 Tampermonkey 插件。

Stylus 能够使用被称为 user.css 的技术,能够在本地修改任意网站的样式 – 即自定义 UI 显示。
而 Tampermonkey 则更强大,支持 user.js – 可以在本地打开任意网站时载入自定义的 JavaScript 脚本,不再局限于修改 UI,几乎与插件无异(事实上它也确实被认为是更轻量的插件)。

原以为就几句 css 的事情,找到了广告的 id,于是吾辈写下了下面这些 css

/*屏蔽动漫花园的广告*/
.ad,
#1280_adv,
#1280_ad > a,
#bebiv3_ad {
  display: none;
}

但结果却是。。。只生效了一半!

屏蔽一半

可以看到,上面两个广告确实被隐藏了,但下面一个却并没有,而且吾辈在控制台直接使用 document.querySelector('#1280_adv') 也获取 dom 会抛出错误 SyntaxError: Document.querySelector: '#1280_adv' is not a valid selector。吾辈是直接复制的 id,理论上来说不会有错才是。

仔细想想,吾辈或许是漏掉了什么。。。于是,吾辈使用 Copy => Copy Selector 功能,有趣的东西出现了,复制出来的内容竟然是 '\31 280_adv',wtf?

嗯,或许吾辈需要冷静一下,尝试使用 document.querySelector("#\\31 280_adv") 获取一下

注意:这里 JS 里面去查询 DOM Selector 的字符串又进行了转义。

Console 获取

OK,确实能够正常拿到。由于这些奇怪的字符在 css 中存在语法错误,那么接下来便用 user.js 去屏蔽掉它们吧!

基本实现如下

;[
  document.querySelector('#\\31 280_adv'),
  document.querySelector('.ad'),
  document.querySelector('#\\31 280_ad > a'),
].forEach((ad) => ad.remove())

甚至吾辈都发到了 GitHubGreasyFork 上了。

然后,有个(万能的)网友就提出,可以转换思路,既然 #\\31 280_adv 在 css 中存在语法错误,那么使用属性选择器过滤 id 将值包裹在 '' 之中不就好了么?此话真是九言劝醒迷途仕,一语惊醒梦中人,吾辈瞬间 GET 到了这个点。

于是吾辈编写出了下面这段 user.css 样式

/*屏蔽动漫花园的广告*/
.ad,
div[id='\31 280_adv'],
div[id='\31 280_ad'] > a,
div[id='bebiv3_ad'] {
  display: none;
}

使用后效果如下

屏蔽后干净的网页

现在,初始目的达成了,吾辈开始有点好奇它是怎么实现这个功能,于是下载了它的源码,id 那里并未发现什么奇怪的东西,但吾辈却也无法复现一个 demo!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <div id="test">2</div>
    <script>
      window.addEventListener('load', () => {
        document.querySelector('#test').setAttribute('id', '\\31 280_adv')
      })
    </script>
  </body>
</html>

demo 效果

demo 效果

如果有人知道原因的话,请务必不吝赐教!

参考:ASCII Wiki


后续,万能的网友 NiaMori 又来说明啦,实际上是 id 以数字开头的原因,具体问题参考:
是 id 以数字开头的原因,简单的 <div id="1">test<div> 就能复现这个效果。
document.getElementById('1') 能够选中,但 document.querySelector('#1') 不能,因为 HTML5 允许 id 以数字开头而 CSS 不允许
0x31 是 ‘1’ 的 Unicode 编码值,Copy selector 的时候 Chrome 做了一个智能的 escape
参考:


文章作者: rxliuli
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 rxliuli !
 上一篇
Android 上最好的浏览器 Kiwi browser Android 上最好的浏览器 Kiwi browser
场景 官网 或许对于现在很多人来说,浏览器是一个很少使用的 App,因为所有功能都可以在 App 做,不需要使用浏览器。一方面,是由于国内的大环境就是把用户当成傻瓜(事实上,即便是吾辈目前所在的公司,在 UI/UX 设计方面也倾向于将用户
2020-05-01 rxliuli
下一篇 
JavaScript 禁止用户保存图片 JavaScript 禁止用户保存图片
场景在业务需求中不希望用户保存图片,因为是一些供内部使用的图片。 思路 添加事件禁止选择、拖拽、右键(简单的禁止用户保存图片,但无法阻止用户打开控制台查看,或是直接抓包) 将之转换为 canvas(让浏览器认为不是图片以此禁止用户对之进行图
2020-04-27 rxliuli
  目录