title: 字体反爬总结
date: 2023-08-23 07:31:19
tags:
简单入门级字体反爬
固定字体编码、固定字体坐标
字体反爬网站的类型特征为网站源代码中出现特殊符号或者是繁体字,与网站上显示有很大区别。其中字体文件的都是固定的不发生变化。
相关参数了解:
“xMin”、“yMin”、"xMax"和"yMax"是表示字形边界框的参数。边界框定义了字形在给定字体中所占用的矩形区域的范围。
在标签下,我们可以看到一系列的标签,每个标签都对应于字形的一个点。每个标签中的"x"和"y"属性表示了该点在字形空间内的坐标位置。
此外,“on"属性的值为"1”,表明该点是一个标记点或拐角点,而不是一个曲线上的控制点。
逆向方法
- 查找字体文件
- 点击F2,打开浏览器工具,在Font面板中功能够发现当前网站加载的字体文件
- 在网页源代码中查找如下代码,一般在class属性中。
@font-face { font-family: <identifier>; src: <fontsrc> [, <fontsrc>]*; <font>; }
- 下载文件,查看映射表
使用FontCreator软件直接可以看到字体映射
直通网址。下载字体文件,获取字典映射,如下两种方法
人工版:只有数字或者少数字符,写出字典映射 程序版:使用fontTools库中的TTFont类获取映射表
newFont = TTFont("newFont.ttf") cmap = newFont.getBestCmap() print(cmap)#{41604: 'unia284', 43159: 'unia897', 43345: 'unia951',...} #cmap中键为10进制整数值,一般显示未16进制 cmap_16 = {hex(key):val for key,val in cmap.items()} print(cmap_16)#{'0xa284': 'unia284', '0xa897': 'unia897', '0xa951': 'unia951',...} print(chr(0xa284))
unia284是指字体中每个字形(字符的可视表示)的唯一标识符。字形名称是一个字符串,用于在字体文件中标识和引用每个字符的具体外观,但unia284 这个词不是一个有效的 Unicode 字符或编码。Unicode 定义了数千个字符,每个都有一个唯一的代码点或代码位,可以用来表示它。uni是前缀,需要转化为unicode字符码,使用chr方法转换。
以 a284 作为 Unicode 码点的字符动态字体编码
从网站上请求两次字体文件,使用以下py代码将下载的ttf文件转化成xml文件,之后观察xml文件,观察每一个字符的x,y坐标信息,x,
y以固定的偏移量进行改变。逆向方法
- 下载文件,不在详述
x,y固定偏移量
观察当前字体文件的偏移量,以其中一个文件(文件A)为已知映射关系,使用coordinates属性来获取字体文件的每一个字符的x,y坐标信息添加到列表中,字体文件的坐标虽然发生变化,但是有固定的偏移量,使用程序判断另一个文件(文件B)的x,y坐标与文件A的对应关系,从而实现新请求下的映射关系表。
代码如下:
from fontTools.ttLib import TTFont class Mapping: def __init__(self,font_path): #本地编辑的已知对应的关系表 self.uni_ls = ['unib745','unia786','unib859','unic491','unia219','unic732','unic946','unic698','unib639','unib173'] self.font = TTFont(font_path) self.font.saveXML('font.xml') #循环已知字体映射关系的字体文件,获取xy参数对应的列表 def get_MappingList(self): be_p2 = [] for n in self.uni_ls: p2 = [] p = self.font['glyf'][n].coordinates for i in p: p2.append(i) be_p2.append(p2) return be_p2 #应对字形名称发生变化,坐标不发生变化的字体反爬,判断字型的xy列表是否相同 def same(self,ls1,ls2): if (len(ls1) != len(ls2)): return False for idx in range(len(ls1)): if (ls1[idx] != ls2[idx]): return False return True #获得新的映射关系字典 def get_NewMapping(self,uni_k,uni_list): dic = {} Map = self.get_MappingList() # #循环从网站上下载下来的列表 for p1 in range(len(uni_list)): print(uni_list[p1]) for p2 in range(len(Map)): if (self.same(uni_list[p1],Map[p2])): print(Map[p2]) dic[uni_k[p1]] = p2 break return dic #得到偏移之后新生成的字体码数组 def get_offsetNewMapping(self,x,y): offsetNewMapping = [] Map = self.get_MappingList() for p2 in Map: print(p2) alpha = [] for a in p2: alpha.append((a[0]+x,a[1]+y))#相对于已知映射文件传入正负值。 print(alpha) offsetNewMapping.append(alpha) return offsetNewMapping # if __name__ == "__main__": # mapping = Mapping('font.ttf') # print(mapping.get_offsetNewMapping(1,1))
x,y动态变化
x,y也发生变化时候,可以通过对比on的值来匹配内容。
获取on值的字符串代码:font = TTFont('font.ttf') name = font.getGlyphOrder() dic = {} str_list = [] for i in name[1:]: str_alpha = "" p = font['glyf'][i].flags for j in p: str_alpha += str(j) print(str_alpha) str_list.append(str_alpha)
案列:猿人学第七题直通网址。
总结
字体反爬先了解到这。
插入一点;
ord() 和 chr() 是 Python 中用于字符和字符代码之间相互转换的函数。
ord(character) 返回字符 character 的 Unicode 码点(字符代码)。
chr(code) 接受一个整数 code(字符代码)并返回对应的字符。
总结来说,ord() 用于将字符转换为其对应的整数值,而chr() 用于将整数值转换为其对应的字符。