发现一种有趣的防爬虫手段

本文所述仅局限于技术层面的探讨,请勿将本文思路用于违法犯罪活动,否则后果自负!

背景

前段时间,有个朋友在群里提到一件怪事:在某网站上,拷贝正常的文本再粘贴到其它地方时,全都是乱码,只能使用网站提供的复制功能。

1
2
看到的文本:笔名
复制的文本:笞吗

这一下子勾起了我极大的兴趣,于是我打开了这个网站,开始研究它里面的门道。

探索过程

监听拷贝事件

听到这个趣事时,我的直觉告诉我,它可能是监听了用户的复制事件,把本来正常的文本转成了乱码。但我很快就被打脸了:

  • 通过浏览器控制台,查看网页源码时,看到的确确实实是乱码
  • 查看 JS 代码,也没有找到任何监听复制事件的逻辑

乱码转换方法

然后,我的探索方向变成:网页下载的是乱码,但通过 JS 内置的转换规则,可以把乱码转成正常文本。但很快,这个思路也走不通了:

  • 通过在 JS 脚本中打断点,一步步观察可疑变量,并没有找到乱码转换的内置逻辑
  • 官方提供的复制功能,实际是通过网络请求获取的正常文本

字体问题

就在一筹莫展的时候,我的一个无意举动,打开了新世界的大门。

在反复浏览它的网页源码时,我发现明明很多字的样式都差不多,但是却给很多段落使用了不同的 font-family,而且这些 font-family 是自定义的,而非标准字体。

于是我随手把某个段落设定的 font-family 去掉,发现原本正常的文本乱码了!也就是说:

  • 网站下载的确实是乱码,但乱码和正常文本的转换关系是在服务端设定好的
  • 通过设定一系列字体,来控制前端乱码转换的效果

这防爬虫手段,真的是不可不谓之妙啊妙啊!

如何破解

以下内容仅作为技术探讨,请勿用于违法犯罪活动,否则后果自负!

OCR 解千愁

其实,最最简单的方法,是不要去理会它的转换关系:直接截图,丢到 OCR 软件中识别,就可以得到正常的文本。但是,OCR 的识别并不总是可靠的。尤其需要拷贝长文本的时候,需要人为去逐字校验一遍,太费眼睛了。

那么,有没有更好一点的办法呢?

找文本编码转换的规律

对于防爬手段不够高明的网站来说,它的乱码和文本之间,可能存在非常简单转换关系,比如仅是 unicode 编码偏移。

1
2
看到的文本:笔名
复制的文本:笞吗

以上面的文本为例, 的 Unicode 为 3150821517,而 的则为 3151821527,两者的差值刚好是 10

所以,在获取到 HTML 文本之后,可以对文本做一个简单的转换,从而得到正确的文本。

1
2
// 笞 => 笔
String.fromCharCode('笞'.charCodeAt(0) - 10)

找字体轮廓的规律

有的时候,网站的文本转换关系可能并不像上述例子中直接,或者它就是没有相对固定的规律。这个时候,就要从字体的轮廓中找找规律了。

一种可行的思路是,通过 opentype.js 或者 FontDrop! 在线工具,分析和对比字体的 Path Data 数据,得到文本的映射关系。

有的时候,网站开发者会对字形做微调,导致轮廓数据无法完美匹配。这种情况下,还可以尝试用一些简单的机器学习算法(如 KNN)找出最相近的文本。

PS:如果要涉及到非常复杂的机器学习算法(甚至是神经网络模型),那还是建议用成熟的 OCR 软件吧!