需求很简单,比方说有时候会关注几个专职搬运视频的号,然后就会发现他们会发些很烦人的图文动态。视频还是想看的,所以需要精确的只屏蔽特定用户的图文动态。b 站本身似乎没这种功能,因为我主要是电脑上浏览器看看b 站动态,所以决定用浏览器的广告屏蔽插件来实现,具体而言,就是添加一条自定义屏蔽规则。
屏蔽插件
我用的firefox 浏览器,插件是这个Adblocker Ultimate,用了挺长时间了,效果一直很强力,除了偶尔会遇上针对广告拦截的,不过规则更新也挺勤快。Chrome 应该也有这个。
广告屏蔽插件的原理多种多样,比如可以直接阻止网络请求、停止脚本的,最简单的类型是根据规则匹配页面上的某个元素,然后把这个元素隐藏掉,正适合拿来做黑名单屏蔽。
要添加自定义规则可以点开设置,里面就有个自定义规则标签页:
每行写一条规则,自动保存。
规则语法
基本的规则语法可以参考这个:Adblock Plus filters explained,差不多是通用。如果要选择并隐藏某个域名下页面中某个或者某一类元素,基本思路就是用CSS 选择器,类似这样:
t.bilibili.com##.target-css
##
后面跟的是标准的CSS 选择器语法,这条规则会把t.bilibili.com 域名下页面上所有.target-css
类的元素隐藏掉。要做的就是打开浏览器控制台,分析页面结构,看看要隐藏的那个元素有什么特别之处。
伪选择器
当然只用标准的CSS 选择器能做的很有限,所以规则中也扩展了所谓的伪选择器(pseudo-selector),形式上有点像CSS 伪类,比如这样:
t.bilibili.com#?#div:has(span:contains(今天给大家推荐))
用了伪选择器的规则要把##
变成#?#
。这条规则的意思是:屏蔽页面上满足条件的div
元素,这些div
的子元素有span
,而这个span
内部的文本含有“今天给大家推荐” 这么几个字。
上面的例子用了伪选择器:has
和:contains
。:has(expr)
的意思是,冒号前的元素,其子元素中含有满足CSS 表达式expr
的元素,如果满足这个条件,冒号前的元素就被选中。伪选择器可以嵌套,所以括号里的CSS 表达式还可以包含伪选择器。:contains(text)
也很简单,就是检查冒号前元素的内部文字是否包含text
,满足条件就选中。
所以包含伪选择器的CSS 表达式需要满足两个条件才能选中某个元素,首先就是满足CSS 选择器,在这个基础上,用CSS 选择器选中的元素还要满足伪选择器的条件才能最后被选中。
伪选择器并列语法
除了嵌套,伪选择器还可以并列,比如:
t.bilibili.com#?#div:has(span):has(table)
这条规则也是选中div
元素,这个div
要满足两个条件,首先是含有span
元素,同时还要含有table
元素。有了这种语法就可以把多个条件组合到一起,实现复杂的选择功能。
其他伪选择器
基本上伪选择器的用法可能都要参考别人的规则文件,反正我是没找着成体系的文档。常见的伪选择器就是:has()
,:contains()
,再加一个:not()
,就是和:has()
的效果相反,选中不满足条件的。
屏蔽动态
现在可以开始研究如何屏蔽动态了。打开浏览器控制台,可以看到:
每条动态卡片就是一个div.bili-dyn-list__item
,把这个元素整个删掉,对应的动态就完全没了。所以基础的屏蔽规则就是:
t.bilibili.com#?#div.bili-dyn-list__item
当然只是这么写的话所有动态都没了,接下来就开始用伪选择器,需要实现两个条件:
- 匹配特定用户,其他的原样保留
- 匹配图文动态,其他的原样保留
两个条件可以分开考虑,最后并列起来就行。
匹配特定用户
最简单的想法是看看动态卡片里有没有哪个链接或者别的元素带有指向用户页面的链接,有的话就能精确的根据用户链接或者id 做匹配。我已经找过了,没有[doge]。所以退而求其次,直接匹配显示出来的用户名文本。鼠标放在用户名上检查元素,可以看到基本是这样的结构:
就是找到这个地方的一个span
,它的内部文本匹配用户名。那么上面的基础规则就可以改成:
t.bilibili.com#?#div.bili-dyn-list__item:has(div.bili-dyn-item__header div.bili-dyn-title span:contains(少女前线后勤组))
意思是要求最前面的动态卡片div
里面有一个span
,span
的内部文本又要匹配用户名,span
前面加了一串元素层级是为了提高容错度,保证选择的是这个表示用户名的span
。
只用这条规则的话,这个用户的所有动态都会被屏蔽。
匹配图文动态
总之是要找到图文动态和其他动态不同的地方,然后匹配这个差异点。我发现的是这个:
只有图文动态有这样的结构,对应动态里面的正文部分。所以基础规则改成这样:
t.bilibili.com#?#div.bili-dyn-list__item:has(div.bili-dyn-content__orig__desc > div.bili-rich-text)
div.bili-rich-text
元素在其他地方也有出现,所以要用css 表达式限制这个父子元素关系。
用这条规则可以无差别屏蔽所有图文动态
并列
然后就很简单了,把上面两个条件中的伪选择器表达式并列起来,就能表达关系与,实现只屏蔽特定用户的图文表达式,规则如下:
t.bilibili.com#?#div.bili-dyn-list__item:has(div.bili-dyn-item__header div.bili-dyn-title span:contains(少女前线后勤组)):has(div.bili-dyn-content__orig__desc > div.bili-rich-text)
注意中间不要加空格。把用户名换成别的,复制粘贴几次就能屏蔽更多用户。
总结
总之还挺好用的,基本上无痕,对浏览器性能也没感觉有什么影响。规则语法简单直观,不像正则那样堪比玄学,希望大家都学会了。
注
如果要屏蔽转发动态,可以把div.bili-dyn-content__orig__desc
改成div.bili-dyn-content__forw__desc
。如果图文和转发都要屏蔽,那就复制粘贴,两条都写上。