今天为大家带来的是字体反爬的另一个案例,汽车之家。与之前不同的是,这里是对汉字的处理。具体来看下面的分析与代码。
首先参考的网站:https://club.autohome.com.cn/bbs/thread/1f05b4da4448439b/76044817-1.html#%23%23
从网站中可以观察到,它的反爬是这样的:
再从网页源码中观察,发现又是这样的:
寻找它的字体文件:
下载保存到本地。
接下来就是字体分析,同样的,先查看字体文件:
这里定义两个列表,一个为汉字列表,一个为编码列表,他们之间的对应关系是按顺序的,即列表的索引,如下所示:
观察后发现,字典中的键值并没有规律和特殊性,还是得通过xml文件观察不同字体文件的区别,生成xml文件代码如下:
from fontTools.ttLib import TTFont from io import BytesIO url_ziti = '字体文件地址' ziti = requests.get(url_ziti) # 下载ttf字体文件,然后通过BytesIO转化为内存文件,使用TTFont处理 font = TTFont(BytesIO(ziti.content)) cmap = font.getBestCmap() font.saveXML(r'C:..\qiche1.xml')
接下来还是放两张图大家感受一下:
这是相同汉字“大”在不同xml文件中的对象,可以发现,同一汉字的对象是不相同的,区别在于对象中每个坐标的差值小于40,于是当有新的字体文件时只需要对比同一汉字的编码其对象的差值是否小于40,如果小于就得到对应的汉字。
如果大家还没有理解,在放两张图让大家感受一下:
铛铛铛铛!!就是你看到的那样,这两个汉字细微的差别就是 每个x,y差值的意义。
对比编码对象的代码如下所示:
def comp(l1,l2):#定义一个比较函数,比较两个列表的坐标信息是否相同 if len(l1)!=len(l2): return False else: mark= 1 for i in range(len(l1)): if abs(l1[i][0]-l2[i][0])< 40 and abs(l1[i][1]-l2[i][1])< 40: pass else: mark= 0 break return mark font1 = TTFont(r'C:..\qiche1.ttf') font2 = TTFont(r'C:..\qiche2.ttf') tup1=[] #保存38个字符的(x,y)信息 for uni in u_list: p=font1['glyf'][uni].coordinates #获取对象的x,y信息 tup1.append(list(p)) tup2=[] for i in uni_list2: p=font2['glyf'][i].coordinates tup2.append(list(p)) n2= 0 x_list=[] for d in tup1: n2+= 1 n1= 0 for a in tup2: n1+= 1 if comp(a,d): print(uni_list2[n2-1],word_list[n1-1]) x_list.append(word_list[n1 -1])
对比过后,打印出字体2编码对应的每一个汉字,结果如下图所示:
与字体二中的内容一致,可见这样的判断是符合要求的(如果大家觉得是偶然因素,可以对比多个字体,看最后的结果是否符合)
字体反爬暂时告一段落,这三个案例是由易到难的一个过程,本质就是寻找一种映射关系,从而在不同的字体文件也能找到对应字符。