AutoJs获取的Text文本是乱码|Android爬虫反字体屏蔽乱码解决方案

源由

AutoJs可以获取Android原生的空间,比如TextView里的文字。实践中发现,大部分的textView是可以正常获取到文本的,但是某些App做了防止爬取的功能,将TextView的字体设置为冷僻的字体,导致即使被获取了文本,也无法正常的显示出来,俗称“乱码”。针对这种问题,我自己另辟途径发现了一个比较完美的解决方案。

方案的原理较为简单,适用性也比较广。通过反编译Apk文件,获取内部的资源,例如字体文件.ttf。得到ttf字体文件以后,可以安装到Windows系统上,然后从手机里复制出无法识别的字体,保存到文本文件,最后把文本文件放在Windows上使用Notepad打开,设置Notepad的字体格式为这个冷僻的字体,正常情况下是可以显示的。

但是需要注意的是,虽然Windows是可以显示这个特殊的字体,但是你可能依然无法输入这个字体。虽然Windows能够轻松安装字体文件,但是Android程序基本是安装不了的。即使安装了,很有可能其他文字例如汉字就会显示乱码。因为你安装的冷僻字体并不一定包含了汉字。就以我这个字体为了,它是在阿里巴巴矢量图库:icon-font自定义矢量图ico生成的ttf字体文件,这个文件内只有字母和阿拉伯数字,所以如果我把这个字体强行安装在Android上,很有可能出现我上面的猜测。而且我也不愿意去安装这个字体。

解决原理

既然Android系统上无法通过安装字体来解决识别问题。那么我们是不是可以尝试自己做一个字体映射,以此来识别文字内容呢?将乱码通过手工在代码里定义成一个常量,表示这个乱码的内容。

例如:1 = #45d 2=#hd2……以此类推,其中45d 和hd2都是乱码。那么我怎么知道乱码是什么?还记得上面复制出来的文本文件吗?虽然现在可以正常显示,但是它在Android系统中就是乱码。学过计算机系统的朋友应该知道,所有的文件最终是以二进制的形式保存在硬盘上,所以虽然我们看起来乱码,但是它的二进制内容是不会丢的。

因此,我们可以选择以二进制来查看这个文本文件,即可找到这个字符对应的二进制内容,如下图,我通过十六进制查看文本文件:

字体映射

其实上图有误导性。因为记事本打开的这个文件和用editplus打开的文件不是同一个文件。记事本打开的“字体测试”是修改后的,而editplus打开的“字体测试”不是最新的,这是前提。

当editplus里的光标放在十六进制区域的31上面的时候,右边十进制的区域1被选中了,说明十六进制的31是等于十进制的1,为什么这样?因为这是使用了ASCII码表,具体如下图:

ASCII码表

从ASCII码表中可以看到字符`1``的十进制是编码是49,把49转成十六进制刚好是31,如下图:

49转十六进制

由此可知31确实等于字符串1,恰好和右边的十进制区域内的1对应了。

0A则是对应着换行符,不信的话可以查找上面的ASCII码表,换行符的编码是10,10转十六进制为0A。

那么31左边的3位是什么?聪明的朋友可能想到了,这就是那个特殊字体,在这个“字体测试”文件中,我用数字1和换行符来做分割,从数字0~9依次列举出来了。所以在31 0A的左边3位十六进制,代表着一个特殊字体的数字。

所以由此可以知道:EE A4 8E便等于0,EE A4 8F等于1,EE A4 90等于2,EE A4 91`等于3……以此类推一直到9。所以我们只需要读取特殊字体的文本,然后转行成十六进制,再和上面的字符串进行比对就知道特殊字体的文本的含义了,是不是很简单?

改进一下

另外如果你观察的足够仔细的话,三位十六进制,前两位是不变的,变动的只是第三位,所以如果实际上09的十个数字的十六进制是:8E + 10,8E的十进制=142。142 + 10 = 152。152的十进制是98。所以09的特殊字体的十六进制的区间是:8E~98。

编码

既然十六进制的含义都解决了,剩下就是编码了。编码思路如下:

  1. 读取特殊字体的文本
  2. 将文本转换成十六进制
  3. 将十六进制的位数/3,因为每3位代表一个数字
  4. 根据上面解析的十六进制对照表,来判断出字符串应有的含义