前几天我们说到这个猫眼的字体反爬,其自定义字体定义的都是数字,而今天我们要尝试破解的是汽车之家的汉字字体反爬,现在就来一探究竟吧!
可以看到其中的“更”字在查看元素的时候显示为小框,可见这就是该网站的一种反爬措施了。
我们先找其自定义字体文件,我们在网页源代码中搜索font-face,就能够在其中有该文件的链接。
这是一个ttf文件,我们采用FontCreator软件来观察。字体文件导入之后的效果如下:
如果每个页面都是相同的自定义字体文件,那我们可以直接构造映射并完成对字体的反反爬。现实果然很残酷,每个不同的页面都有不同的字体文件,但是幸运的是,每个字体文件包含的汉字数目和类型是完全相同的。再打开一个网页上的字体文件来观察。
只是变换了name而已,那岂不是跟猫眼的数字字体反爬一模一样了吗。
我们利用fontTools,把这两个字体文件给存储为xml来看看这个字体对象是如何定义的吧~我们以“右”这个字为例,
是不是能找到一些规律呢?同一汉字的对象是不相同的,但是区别是微小的,对象中每个坐标的差值较小,这样我们可以通过限定对象的坐标值差值在一定范围内就可以认为是两个相同的汉字了。
下面是判断字体对象是否表示同一个字的比较函数:
def compare(c1,c2):
"""
输入:某俩个对象字体的坐标列表
输出:bool类型,True则可视为是同一个字
"""
if len(c1)!=len(c2):
return False
else:
for i in range(len(c1)):
if abs(c1[i][0]-c2[i][0])<50 and abs(c1[i][1]-c2[i][1])<50:
pass
else:
return False
return True
然后,利用相同的思路,下载新的ttf字体文件,将其与先有的base.ttf文件进行比较,若两个name表示相同的汉字,则构造新的字典,并将网页中的 等字样根据新的字典变换成汉字。具体代码如下:
def decrypt_font(font1,font2,response):
"""
输入:base字体,新字体以及网页源代码
输出:字体解密后的网页源代码
"""
word_list=['九','呢','着','地','得','的','五','六','低','右','一','二','远','更','了','好','三','多','小','长','是','坏','十','近','少','八','很','四','短','上','七','下','不','和','高','左','矮','大']
uniname_list1=['uniEC1F', 'uniEC21', 'uniEC39', 'uniEC3B', 'uniEC55', 'uniEC67', 'uniEC71', 'uniEC81', 'uniEC82', 'uniEC8B', 'uniEC9D', 'uniECAE', 'uniECB7', 'uniECB8', 'uniECD3', 'uniECE4', 'uniECED', 'uniECFE', 'uniED00', 'uniED09', 'uniED18', 'uniED1A', 'uniED34', 'uniED36', 'uniED46', 'uniED50', 'uniED61', 'uniED6A', 'uniED7C', 'uniED96', 'uniED97', 'uniEDB2', 'uniEDC3', 'uniEDCC', 'uniEDCD', 'uniEDDD', 'uniEDE8', 'uniEDF9']
uniname_list2=font2.getGlyphNames()[1:]
base_dict=dict(zip(uniname_list1,word_list))
# 保存每个字符的坐标信息,分别存入coordinate_list1和coordinate_list2
coordinate_list1=[]
for uniname in uniname_list1:
# 获取字体对象的横纵坐标信息
coordinate=font1['glyf'][uniname].coordinates
coordinate_list1.append(list(coordinate))
coordinate_list2=[]
for i in uniname_list2:
coordinate=font2['glyf'][i].coordinates
coordinate_list2.append(list(coordinate))
index2=-1
new_dict={}
for name2 in coordinate_list2:
index2+=1
index1=-1
for name1 in coordinate_list1:
index1+=1
if compare(name1,name2):
new_dict[uniname_list2[index2]]=base_dict[uniname_list1[index1]]
for uniname in uniname_list2:
pattern='&#x'+uniname[3:].lower()+';'
response=re.sub(pattern,new_dict[uniname],response)
return response
其中word_list和uniname_list1是通过FontCreator软件一一对应记录下来的,即构造了一个base字典,作为参照。
通过之前几篇JS解密、app抓包和字体反爬,我们可以看到,在分析网页分析代码的时候需要利用好多种多样的工具来帮助我们完成所要信息的爬取。选对工具,才能事半功倍~
喜欢就点个赞吧❤