隐式 Style–CSS 在反爬虫中的应用

2,385 阅读6分钟

文章作者:「夜幕团队 NightTeam」 - 戴煌金

润色、校对:「夜幕团队 NightTeam」 - Loco

什么是隐式 Style–CSS

先来唠唠什么是 隐式 Style–CSS:

CSS中,::before 创建一个伪元素,其将成为匹配选中的元素的第一个子元素。常通过 content 属性来为一个元素添加修饰性的内容。

引用自:developer.mozilla.org/zh-CN/docs/…

上面的这段话对于没做过前端开发的朋友而言,看着可能会有点难懂,没关系,我们用个例子简单地演示一下。

我们新建一个 HTML 文件输入下面这样的内容:

<q>大家好,我是咸鱼</q><q>我是 NightTeam 的一员</q>

并在这个 HTML 中引用下面这个样式文件:

q::before { 
  content: "«";
  color: blue;
}
q::after { 
  content: "»";
  color: red;
}

最后在浏览器中展示的内容是这样的:

可以看到在上面的例子里,我在 HTML 源码里隐藏了文字前后的符号,但是经过浏览器渲染后,文字前后的符号就出现了,是不是很神奇?

目前很多小说网站都使用了类似这样的反爬虫技术,用来保护自己的内容不被爬虫爬取。

实例讲解

那么类似这样的反爬技术应该怎么处理呢?咸鱼准备了一个例子简单实战一下,用实例讲讲我遇到这类反爬是如何处理的。

发送消息【隐式Style-CSS】到我们的微信公众号【NightTeam】即可获取样例地址~

由于这个例子比较简单,所以这里我就省略掉分析请求的步骤了,直接来分析一下浏览器看到的效果与源码分别长什么样,找找有没有什么突破口吧。

这是浏览器看到的效果:

浏览器效果

这是源码:

HTML 源码

可以在源码中看到部分内容被 <span class="context_kwx"></span> 替换。

页面分析

打开浏览器的开发者模式,看看隐藏的文字是什么样子的:

可以看到在上图中,Styles 栏(图中标注 2 的位置,意为元素对应的 CSS 信息) 中 content 的内容正是 HTML 中被隐藏的内容(图中标注 1 的位置)。

这正符合我们在第一部分关于“隐式 Style-CSS”的举例。

那么我们只需要把被替换掉的 span 标签替换回 CSS 里设置的 content 的值就可以了。


如果是正常的页面结构,CSS 是被直接放在 HTML 源码里或某个 .css 文件中的,我们只需要在 Styles 栏中点击右侧的文件名就可以直接跳转到 CSS 文档所在的位置了,如下图:

但是在我们的这个页面中,Styles 栏里并没有这样可以点击的位置,这代表了这个部分的 CSS 不是直接放在某个文件里的,而是通过特殊手段动态添加上去的,所以我们只能通过分析 span 标签的规律找找突破口。


从 HTML 源码中可以看到,所有的 span 标签的类名都是 context_kw 加上一个数字拼接的,我们可以试着搜索 context_kw 看看。

于是我们就搜到了一些 context_kw 相关的 JS 代码:

我们大致浏览一下整段 JS 代码。这段 JS 通过功能分为两个部分:

第一部分:CryptoJS 的加解密的逻辑内容,可以忽略。

第二部分:经过混淆的内容,第二部分的 JS 对数组中的密文进行解密,并操作了 DOM ,将 JS 与 CSS 结合,完成了反爬最主要的逻辑。

JS 代码分析

根据第二部分中操作 DOM 的代码,我们找到关键变量 words

for (var i = 0x0; i < words[_0xea12('0x18')]; i++) {
            try {
                document[_0xea12('0x2a')][0x0][_0xea12('0x2b')]('.context_kw' + i + _0xea12('0x2c'), 'content:\x20\x22' + words[i] + '\x22');
            } catch (_0x527f83) {
                document['styleSheets'][0x0]['insertRule'](_0xea12('0x2d') + i + _0xea12('0x2e') + words[i] + '\x22}', document[_0xea12('0x2a')][0x0][_0xea12('0x2f')][_0xea12('0x18')]);
            }
        }

再继续找到 words 变量声明的地方。

var secWords = decrypted[_0xea12('0x16')](CryptoJS['enc']['Utf8'])[_0xea12('0x17')](',');
var words = new Array(secWords[_0xea12('0x18')]);

按照这个方法,我们最后发现 CSS 的 content 的内容都是数组 _0xa12e 中一个经过加密的元素先经过 AES 解密再经过一定处理后得到的值。

有了这样的一个逻辑框架之后,我们就可以开始抠出我们需要的 JS 代码了。

JS 代码调整

这个代码虽然经过混淆,但还是比较简单的,所以具体的抠代码步骤就不演示了,这里提示一下在抠出代码之后两个需要改写的点。

第一个是下图中的异常捕获,这里判断了当前的 URL 是否为原网站的,但是我们在 Node 环境下执行是没有 window 属性的,如果不做修改会出现异常,所以需要把这里的 if 判断语句注释掉。

第二个是下图中在返回时的判断语句,同样是对 Node 中不存在的属性进行判断,所以也需要在这里进行相应的修改。

第二个修改点可以像这样改:

_0x1532b6[_0xea12('0x26')](_0x490c80, 0x3 * +!('object' === _0xea12('0x27')))

以上两点修改完后就可以获取到所有被替换过的字符了,接下来只需要把它们替换进 HTML 里就可以还原出正常的页面。替换的步骤这里就不再演示了,因为非常简单,一看就会。

总结

本文简单介绍了隐式 Style–CSS 在反爬虫中的应用,并通过一个简单的实例学习了如何应对这种情况,相信尝试过的你已经清楚地知道下次碰到这种反爬的时候该如何破解了。

当然呢,这个例子还不够完善,没有完全覆盖到隐式 Style–CSS 在反爬虫中的所有应用方式,如果读者朋友对这类反爬虫有兴趣的话,不妨多找几个例子自己动手试试,也欢迎通过留言区与我交流讨论。

发送消息【隐式Style-CSS】到我们的微信公众号【NightTeam】即可获取样例地址~


夜幕团队成立于 2019 年,团队包括崔庆才、周子淇、陈祥安、唐轶飞、冯威、蔡晋、戴煌金、张冶青和韦世东。

涉猎的编程语言包括但不限于 Python、Rust、C++、Go,领域涵盖爬虫、深度学习、服务研发、对象存储等。团队非正亦非邪,只做认为对的事情,请大家小心。