【机器学习】KNN算法及其用KNN解决字体反爬

KNN算法及其用KNN解决字体反爬

  • 关于KNN算法
    • 概要
    • 简介
    • 原理
  • KNN算法Python实现
  • KNN解决字体反爬
    • web-font介绍
    • 例子
  • 最后

关于KNN算法

概要

  • K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。

  • KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合。

简介

  • 下图中,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。
    【机器学习】KNN算法及其用KNN解决字体反爬_第1张图片
  • K最近邻(k-NearestNeighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。
  • kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
  • KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成反比。

原理

首先先抛出欧几里得距离公式:
在这里插入图片描述
这个公式表示的是在n维空间内,任意两点之间的欧式距离。
举个例子已知两个类别的量化点为:
A类别->x点的量化坐标为(0, 0, 2, 5);
B类别->y点的量化坐标为(1, 1, 5, 2);
已知一个未知点C量化坐标为(0, 1, 2, 4);
经过计算代入公式:
在维度为1的情况下C与A、B两点的距离分别为0, -1
在维度为2的情况下C与A、B两点的距离分别为1, 0
在维度为3的情况下C与A、B两点的距离分别为0, -3
在维度为4的情况下C与A、B两点的距离分别为-1, 2
再经过公式后,负距离的都会变成正的。最后通过数值得到,A与C的距离值是最小的,所以就把C归类为A。

KNN算法Python实现

在实际应用中,通常已知类别都是很多行的,如果只用for,while循环等一个一个进行计算必然会很影响效率,这时候我们一般都是应该使用numpy进行计算,将多行多列的相同维度的数据变成一个矩阵,之后我们都是使用矩阵进行运算(不太熟悉矩阵运算规则的可以查询一下线性代数的相关知识),因为python的矩阵运算是用多线程机制,运算速度比普通循环速度快很多。
算法流程:

  • 准备数据。将数据转为矩阵,数据是指量化过后的数据(1、只包含数字;2、相同维度)
  • 准备标签数据。标签数据应为一维数据(如果是矩阵可以将矩阵先扁平化),直接使用下标取值。
  • 将输入矩阵与已有的矩阵进行矩阵减法,算出距离。前提是先把一维的输入矩阵复制多行(python语句np.tile()),使得矩阵与已有的矩阵阶数相同才能进行减法。ps:在Python的numpy中,好像不用扩展输入矩阵,有一个机制会自动匹配已有矩阵的阶数,当进行减法的时候,会自动将输入矩阵变成与已有矩阵相同阶数,不过要相同行数才行。
  • 矩阵进行平方运算。
  • 将矩阵的每一行求和。
  • 将矩阵进行更号运算。
  • 根据距离大小,将距离最小的值对应的索引放到前面,第二小的放第二,以此类推。
  • 根据输入的k范围,计算在k范围内,包含已知矩阵的哪些类别数目最多,返回这个类别的标签
    下面贴出代码
def classify_knn(input_x: np.ndarray or list, dataSet: np.ndarray or list, labels: np.ndarray or list, k:int)->list:
    '''
    :param input_x:     data for predicting
    :param dataSet:     dataset for training
    :param labels:   The labels of dataset
    :param k:   The range of a point of input_x
    :return list:  A list of probability which have minimum distance

    Either input_x or dataSet, they're should to normalize at first
    '''
    dataSet = np.array(dataSet)
    labels = np.array(labels).flatten()  # flattening (扁平化)
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(input_x, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)  # Turning the sum of every rows to 1*dataSetSize matrix
    distances = sqDistances**0.5
    # Return a sorted(fr min to huge) index list of the value of 1*dataSetSize matrix
    sortedDistIndicies = distances.argsort()
    classCount = {
     }
    for i in range(k):  # Place k numbers of labels/type to classCount keys, and add the values of classCount[label[k]]
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # sorted by values(the labels times)
    return sortedClassCount[0][0]

有了这个,我们就可以愉快的进行各种分类问题了。
另外,有另一个问题,如果各维度的值相差较大,不在同一个数量级的话,就要将输入数据和已有的数据都要进行归一化处理,再进行KNN比较好,为什么呢?具体的话看我之前写过的文章。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
https://blog.csdn.net/weixin_41861700/article/details/103100243

KNN解决字体反爬

这次学习用某某点评的例子作为案例:

web-font介绍

web-font是CSS3中的一种标记 @font-face,在@font-face声明里,你可以声明一种字体,指定这种字体字体库文件从网络某个地址下载。

具体写法如下:

@font-face {
    font-family: '字体名称';
    src:  url('http://www.example.com/字体名称.eot'); /* IE9 Compat Modes */
    src:  url('http://www.example.com/字体名称.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('http://www.example.com/字体名称.ttf') format('truetype'), /* Safari, Android, iOS */
    url('http://www.example.com/字体名称.woff') format('woff'),  /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
    url('http://www.example.com/字体名称.svg?#字体名称') format('svg'); /* Legacy iOS */
}

当网页数据需要使用特别的字体来修饰时,我们就可以使用web-font。因为使用web-font会自动从网络中加载字体,并不需要用户本机有安装这个字体。

例子

从某某点评看到,上面清楚的写到什么信息用了什么字体文件。
点开Font,下载对应的woff文件并打开,可以发现如下图:
【机器学习】KNN算法及其用KNN解决字体反爬_第2张图片
每一个字对应有一个uni码,但是通常这个值是变化的,那怎么办呢?
我们可以利用fontTools这个第三方库,来对这些字体文件进行操作

from fontTools.ttLib import TTFont
font_1 = TTFont('base.woff')
font_1.saveXML('base_font.xml')

我们打开这个xml,这些个id不用理睬,并不代表真正的数字,我们前面通过FontEditor 百度字体编辑器 已找到对应数字关系

比如’uniE7F9’代表数字’7’,在这个文件中找下
【机器学习】KNN算法及其用KNN解决字体反爬_第3张图片
我们刷新网页重新获取一个woff文件,重复上面操作
这里’uniEFAC’代表数字’7’ ,保存为xml打开
【机器学习】KNN算法及其用KNN解决字体反爬_第4张图片
发现了嘛,这两个不同字体文件中对数字 '7’的描述(TTGlyph 字形位置x,y,on这些)是完全一致的,仅仅是不同的字体文件它对’7’的命名不同,同时观察其他数字也能得到相同的结论。这样我们就找到了问题的关键,只要TTGlyph对象相同,它所表示的就是相同的数字。有时候,这些字形位置只会改变很小,因为如果变化很大的话,字就会变化了。
思路:
【机器学习】KNN算法及其用KNN解决字体反爬_第5张图片
1.下载一个字体做基准,建立基准字体unicode和文字关系。

2.刷新后的新字体记为网站字体2,匹配网站字体1和网站字体2的字形找到两种unicode的联系。

3.相同的unicode找到字体库和unicode的关系,最后unicode替换成文字。

下面我们使用KNN。

  • 准备字体,将woff的排版的字通过各大平台的ocr识别下来,得到
font_chi = ' .1234567890店中美家馆小车大市公酒行国品发电金心业商司超生装园场食有新限天面工服海华水房饰城乐汽香部利子老' \
           '艺花专东肉菜学福饭人百餐茶务通味所山区门药银农龙停尚安广鑫二容动南具源兴鲜记时机烤文康信果阳理锅宝达地儿' \
           '衣特产西批坊州牛佳化五米修爱北养卖建材三会鸡室红站德王光名丽油院堂烧江社合星货型村自科快便日民营和活童明' \
           '器烟育宾精屋经居庄石顺林尔县手厅销用好客火雅盛体旅之鞋辣作粉包楼校鱼平彩上吧保永万物教吃设医正造丰健点汤' \
           '网庆技斯洗料配汇木缘加麻联卫川泰色世方寓风幼羊烫来高厂兰阿贝皮全女拉成云维贸道术运都口博河瑞宏京际路祥青' \
           '镇厨培力惠连马鸿钢训影甲助窗布富牌头四多妆吉苑沙恒隆春干饼氏里三管诚制售嘉长轩杂副清计黄讯太鸭号街交与叉' \
           '附近层旁对巷栋环省桥湖段乡厦府铺內侧元购前幢滨处向座下噥凤港开关景泉塘放昌线湾政步宁解白田町溪十八古双胜' \
           '本单同九迎第台玉锦底后七斜期武岭松角纪朝峰六振珠局岗洲横边济井办汉代临弄团外塔杨铁浦字年岛陵原梅进荣友虹' \
           '央桂沿事津凯莲丁秀柳集紫旗张谷的是不了很还个也这我就在以可到错没去过感次要比觉看得说常真们但最喜哈么别位' \
           '能较境非为欢然他挺着价那意种想出员两推做排实分间甜度起满给热完格荐喝等其再几只现朋候样直而买于般豆量选奶' \
           '打每评少算又因情找些份置适什蛋师气你姐棒试总定啊足级整带虾如态且尝主话强当更板知己无酸让入啦式笑赞片酱差' \
           '像提队走嫩才刚午接重串回晚微周值费性桌拍跟块调糕'
  • 将已有的数据uni码对应写成映射关系
font_dict = {
     'glyph00000': ' ', 'x': '.', 'unif347': '1', 'unie5fb': '2', 'unie607': '3', 'unif37a': '4',
            'unie1a3': '5', 'unif4f2': '6', 'unif01a': '7', 'unieb4f': '8', 'unif67a': '9', 'unif21e': '0',
            'unie208': '店', 'unif002': '中', 'unif756': '美', 'unif10a': '家', 'unie25b': '馆', 'uniea7e': '小',
            'uniea2b': '车', 'unie77a': '大', 'unief33': '市', 'unied96': '公', 'unied7c': '酒', 'unie9ce': '行',
            'unif8de': '国', 'unif447': '品', 'unie819': '发', 'uniee90': '电', 'unie7ce': '金', 'unie557': '心',
            'unieec2': '业', 'unie5e1': '商', 'unieace': '司', 'unie709': '超', 'unif738': '生', 'unif646': '装',
            'unie266': '园', 'unie2dc': '场', 'uniea0a': '食', 'unif3df': '有', 'unif1d7': '新', 'unif38a': '限',
            'unie4e5': '天', 'unif80f': '面', 'unie09e': '工', 'unie1df': '服', 'unie7bf': '海', 'unie8cf': '华',
            'unif538': '水', 'unie68a': '房', 'unif7b4': '饰', 'uniefed': '城', 'unif3e2': '乐', 'unie832': '汽',
            'uniea50': '香', 'unif64b': '部', 'unie637': '利', 'unif2b4': '子', 'unif43c': '老', 'unif282': '艺',
            'unie1e1': '花', 'unie696': '专', 'unie954': '东', 'uniec76': '肉', 'unif0e9': '菜', 'unie7db': '学',
            'uniec32': '福', 'unie76c': '饭', 'unieb8b': '人', 'unif106': '百', 'unieb18': '餐', 'unif8b0': '茶',
            'unie513': '务', 'unie18f': '通', 'unieb5e': '味', 'unif4b5': '所', 'uniedec': '山', 'unif2f7': '区',
            'unif4ab': '门', 'unie585': '药', 'unie5f0': '银', 'uniee6e': '农', 'unie581': '龙', 'uniea6e': '停',
            'unie6aa': '尚', 'unif5fc': '安', 'unif87b': '广', 'unieb2c': '鑫', 'unie0ac': '二', 'unif750': '容',
            'unie22a': '动', 'unif86b': '南', 'unie011': '具', 'unie4be': '源', 'unie4ae': '兴', 'unif8f0': '鲜',
            'unief48': '记', 'unie54f': '时', 'unieaf2': '机', 'unieb69': '烤', 'unieee3': '文', 'unif58a': '康',
            'uniea24': '信', 'unie751': '果', 'unied85': '阳', 'uniee30': '理', 'unie6e4': '锅', 'unif18a': '宝',
            'unieb4b': '达', 'unif1b4': '地', 'unif251': '儿', 'unif833': '衣', 'unief78': '特', 'unif627': '产',
            'unif288': '西', 'unie4ab': '批', 'uniec8d': '坊', 'unie0e0': '州', 'uniec0c': '牛', 'unie7be': '佳',
            'unie556': '化', 'unie43f': '五', 'unie238': '米', 'unie296': '修', 'uniea14': '爱', 'unif5f6': '北',
            'unie003': '养', 'unie01b': '卖', 'unif39a': '建', 'unif528': '材', 'unif800': '三', 'unif611': '会',
            'unie404': '鸡', 'unif492': '室', 'unif132': '红', 'unie4f1': '站', 'unieb13': '德', 'unieead': '王',
            'unie97f': '光', 'unif8d6': '名', 'uniec06': '丽', 'unif269': '油', 'unied4a': '院', 'unif372': '堂',
            'unied3c': '烧', 'unif5a6': '江', 'unie43c': '社', 'unif048': '合', 'unie4b8': '星', 'unie539': '货',
            'unie710': '型', 'unie53b': '村', 'unieb6b': '自', 'uniec93': '科', 'unif4de': '快', 'unif5d0': '便',
            'unif64c': '日', 'uniee12': '民', 'unieafd': '营', 'unie56f': '和', 'uniedfb': '活', 'unif609': '童',
            'unif544': '明', 'unie4a2': '器', 'unif8a8': '烟', 'unie622': '育', 'unief11': '宾', 'unie410': '精',
            'unie541': '屋', 'unif0f0': '经', 'unieffa': '居', 'unie94e': '庄', 'uniec28': '石', 'unif1c4': '顺',
            'unie81e': '林', 'unief62': '尔', 'unif22e': '县', 'unif854': '手', 'unif072': '厅', 'unif3b4': '销',
            'uniea63': '用', 'unif706': '好', 'unif417': '客', 'unif5ba': '火', 'unif76a': '雅', 'unif044': '盛',
            'unif466': '体', 'unie078': '旅', 'unie991': '之', 'unie031': '鞋', 'unie8ae': '辣', 'unif2ca': '作',
            'unif3e1': '粉', 'unie601': '包', 'unif3ff': '楼', 'unif5d8': '校', 'uniecd4': '鱼', 'unieb06': '平',
            'unieb9b': '彩', 'unie39b': '上', 'uniec98': '吧', 'unif404': '保', 'unie5d0': '永', 'uniec0f': '万',
            'unieaeb': '物', 'unif014': '教', 'unie167': '吃', 'unie843': '设', 'unif415': '医', 'unif7fa': '正',
            'unif5d2': '造', 'unieac6': '丰', 'unie224': '健', 'unif88d': '点', 'unie806': '汤', 'unie13b': '网',
            'unif62c': '庆', 'unie949': '技', 'unie7ba': '斯', 'unie1c5': '洗', 'unie58a': '料', 'unif794': '配',
            'unie189': '汇', 'unie54d': '木', 'unif381': '缘', 'unie5b3': '加', 'unif79a': '麻', 'unie553': '联',
            'unif813': '卫', 'unie5b4': '川', 'unied27': '泰', 'unie20e': '色', 'unif7d0': '世', 'unif13f': '方',
            'unie232': '寓', 'unie288': '风', 'unie16d': '幼', 'unie63f': '羊', 'unief5c': '烫', 'unif675': '来',
            'unif5c3': '高', 'unie61b': '厂', 'unie894': '兰', 'unie4b1': '阿', 'unif2f8': '贝', 'unif144': '皮',
            'unieba3': '全', 'unif694': '女', 'unie221': '拉', 'unie2b6': '成', 'unif48a': '云', 'unif64a': '维',
            'uniea91': '贸', 'uniec86': '道', 'unie7fb': '术', 'uniecde': '运', 'unie150': '都', 'unif012': '口',
            'unie0e6': '博', 'unie40d': '河', 'uniebe1': '瑞', 'unieaf0': '宏', 'unif5ae': '京', 'uniec37': '际',
            'unie20a': '路', 'unie201': '祥', 'unie080': '青', 'unie9ae': '镇', 'unie979': '厨', 'unieb62': '培',
            'unied3b': '力', 'unieebc': '惠', 'uniee49': '连', 'unif8ac': '马', 'unief87': '鸿', 'unie24c': '钢',
            'unie0ab': '训', 'unief01': '影', 'uniee27': '甲', 'unif433': '助', 'uniecb5': '窗', 'uniec84': '布',
            'unif89f': '富', 'unif7e3': '牌', 'uniea1a': '头', 'unif770': '四', 'unie5e7': '多', 'unif89a': '妆',
            'unie2b8': '吉', 'unie428': '苑', 'unie3eb': '沙', 'unie6ad': '恒', 'unie57a': '隆', 'uniead2': '春',
            'unie4e9': '干', 'unif04a': '饼', 'unif749': '氏', 'unie06f': '里', 'unif078': '三', 'unieb80': '管',
            'uniec91': '诚', 'unied29': '制', 'unif088': '售', 'unieadb': '嘉', 'unif15d': '长', 'unie359': '轩',
            'unif530': '杂', 'unie3aa': '副', 'unif7d2': '清', 'uniebc6': '计', 'unif595': '黄', 'unif66c': '讯',
            'unif70f': '太', 'unie90e': '鸭', 'uniebc2': '号', 'unif0b2': '街', 'unieb23': '交', 'unie180': '与',
            'unie152': '叉', 'unif677': '附', 'unie875': '近', 'unie450': '层', 'unie688': '旁', 'unif8b5': '对',
            'unied11': '巷', 'uniee83': '栋', 'unie41b': '环', 'unie58b': '省', 'unie3af': '桥', 'unif2e9': '湖',
            'unie653': '段', 'unie638': '乡', 'unie7a7': '厦', 'unif023': '府', 'unif84d': '铺', 'unief0a': '內',
            'unie24d': '侧', 'unie897': '元', 'unie822': '购', 'unie971': '前', 'unie37b': '幢', 'unif658': '滨',
            'unie80e': '处', 'unie7e2': '向', 'unie2a1': '座', 'uniec53': '下', 'unie987': '噥', 'unief17': '凤',
            'unie06a': '港', 'unie25e': '开', 'unie19b': '关', 'unif39c': '景', 'unif1d3': '泉', 'unief50': '塘',
            'unif4a8': '放', 'unie166': '昌', 'unie578': '线', 'uniebb4': '湾', 'unif54e': '政', 'unie12d': '步',
            'unif298': '宁', 'uniebee': '解', 'uniefd9': '白', 'uniea54': '田', 'unif1ed': '町', 'unied5b': '溪',
            'uniefb2': '十', 'unif231': '八', 'unif43a': '古', 'unif326': '双', 'unieea5': '胜', 'unieda0': '本',
            'unie1f9': '单', 'unie5c2': '同', 'unief60': '九', 'unif380': '迎', 'unie9d4': '第', 'unif8dd': '台',
            'unie57e': '玉', 'unie889': '锦', 'unif78a': '底', 'unif27a': '后', 'unieb8d': '七', 'unie2f3': '斜',
            'unie90c': '期', 'uniebd2': '武', 'unif526': '岭', 'uniea94': '松', 'unie92e': '角', 'unie923': '纪',
            'unif287': '朝', 'unif0ef': '峰', 'unieea9': '六', 'uniea90': '振', 'unif307': '珠', 'unie811': '局',
            'unie6ef': '岗', 'unie9cc': '洲', 'unie57d': '横', 'unie935': '边', 'unie9da': '济', 'unif867': '井',
            'unif300': '办', 'unif194': '汉', 'unie064': '代', 'unif36f': '临', 'uniebc1': '弄', 'unied54': '团',
            'uniedce': '外', 'unie974': '塔', 'uniefcd': '杨', 'unie05d': '铁', 'unie3bd': '浦', 'unif696': '字',
            'unie88a': '年', 'unif8fd': '岛', 'unie7da': '陵', 'uniec29': '原', 'unie99f': '梅', 'unif405': '进',
            'uniea03': '荣', 'unif29a': '友', 'unie9e2': '虹', 'unie379': '央', 'unif0f3': '桂', 'uniea85': '沿',
            'unif6f8': '事', 'unie87f': '津', 'unie5c3': '凯', 'unie91c': '莲', 'unied0b': '丁', 'unie457': '秀',
            'unie378': '柳', 'unie626': '集', 'uniee13': '紫', 'unie154': '旗', 'unie535': '张', 'unif870': '谷',
            'unie119': '的', 'unie6d9': '是', 'unif484': '不', 'unie71e': '了', 'unie732': '很', 'unie4cf': '还',
            'unif04b': '个', 'unie3db': '也', 'unied72': '这', 'unie69f': '我', 'unif2a4': '就', 'unie33e': '在',
            'unieaf8': '以', 'unif059': '可', 'unieb6a': '到', 'unie769': '错', 'unif33b': '没', 'unif880': '去',
            'unie70d': '过', 'unie320': '感', 'unif371': '次', 'unie42e': '要', 'unif375': '比', 'unif318': '觉',
            'unief6e': '看', 'unie018': '得', 'unieee8': '说', 'unif1a9': '常', 'unif28b': '真', 'unif01e': '们',
            'unie0df': '但', 'unif4e0': '最', 'unif310': '喜', 'unied9c': '哈', 'unif5e7': '么', 'unif3a0': '别',
            'unif3a9': '位', 'unif14f': '能', 'unieb35': '较', 'unie4b7': '境', 'unif2cf': '非', 'unie13d': '为',
            'uniec2d': '欢', 'unif4a6': '然', 'unief30': '他', 'unie2cb': '挺', 'unie9c2': '着', 'unie866': '价',
            'unif157': '那', 'unif61f': '意', 'unif4e1': '种', 'unif765': '想', 'unif545': '出', 'unif893': '员',
            'unie838': '两', 'unif7c0': '推', 'unie621': '做', 'unied73': '排', 'uniea48': '实', 'unif430': '分',
            'unif7ec': '间', 'unie2ea': '甜', 'unif19c': '度', 'unie29f': '起', 'unief00': '满', 'unif2ab': '给',
            'uniefde': '热', 'unie49a': '完', 'uniec23': '格', 'unif38b': '荐', 'uniee0f': '喝', 'uniee33': '等',
            'unif82a': '其', 'unieb4a': '再', 'uniedaf': '几', 'unie983': '只', 'unieffe': '现', 'unie32c': '朋',
            'unie02e': '候', 'unied6e': '样', 'unif53a': '直', 'unif767': '而', 'unie305': '买', 'unie51f': '于',
            'unif1b3': '般', 'unie733': '豆', 'unie85d': '量', 'unif724': '选', 'unif3b8': '奶', 'uniee57': '打',
            'unie6b4': '每', 'unie0ae': '评', 'unie417': '少', 'unif4fc': '算', 'unif4a7': '又', 'unie0b7': '因',
            'unie59e': '情', 'unif63f': '找', 'unif13c': '些', 'uniefbc': '份', 'unie047': '置', 'unie5c4': '适',
            'uniec33': '什', 'unif58c': '蛋', 'unieb8e': '师', 'unif0d3': '气', 'unie7a3': '你', 'unif7dd': '姐',
            'unif120': '棒', 'uniee9e': '试', 'unif069': '总', 'unief71': '定', 'uniede2': '啊', 'unie620': '足',
            'unif5e8': '级', 'unie038': '整', 'unie2c3': '带', 'unie2ca': '虾', 'unie30e': '如', 'unie4f3': '态',
            'unie906': '且', 'unif1fa': '尝', 'unie69b': '主', 'unie0a9': '话', 'unif2a3': '强', 'uniecb4': '当',
            'uniea31': '更', 'unie371': '板', 'unif71e': '知', 'unif5ea': '己', 'unie74b': '无', 'uniec2e': '酸',
            'unif703': '让', 'unie682': '入', 'uniee50': '啦', 'uniefb4': '式', 'unie642': '笑', 'unif418': '赞',
            'unie2c8': '片', 'uniefac': '酱', 'unief35': '差', 'unif05b': '像', 'unief38': '提', 'unif29f': '队',
            'unied5f': '走', 'unif438': '嫩', 'unieac5': '才', 'uniecf9': '刚', 'uniee82': '午', 'unif6c4': '接',
            'unif12a': '重', 'uniec92': '串', 'unif54a': '回', 'unie73a': '晚', 'unie677': '微', 'unie397': '周',
            'unie239': '值', 'unie7b0': '费', 'unif0dc': '性', 'unif3e4': '桌', 'unif271': '拍', 'unie1bc': '跟',
            'unie8e1': '块', 'uniec4e': '调', 'unie69e': '糕'}
  • 通过TTfont拿到各个字的字形位置,并统一化。就是一些字的字形位置信息仅包含很少信息,而有些复杂一点的字的字形位置信息很多,这时候就可以通过不够长度的补0来对数据进行统一化。
  • 通过输入预测矩阵, 拿到距离最小的点的标签,也就是原有数据的uni码,通过字典映射,从而拿到实际值。
    下面贴出代码
# 训练用
data_list1 = get_offset_font('3aefeca3.xml')
group = np.array(data_list1)[:, 1:].tolist()
labels = get_label_font(np.array(data_list1)[:, :1])
normalize_group = KNN.normalize_data_z_score_arctan(group)
# 测试用
data_list2 = get_offset_font('892bb594.xml')
test_group = np.array(data_list2)[:, 1:].tolist()
test_labels = get_label_font(np.array(data_list2)[:, :1])
normalize_test_group = KNN.normalize_data_z_score_arctan(test_group)
# 测试字体的映射
test_unicode_list = [TTFont('892bb594.woff').getGlyphName(a) for a in range(603)]
test_dict = {
     i: j for i, j in zip(test_unicode_list, font_chi)}

i ,j = 0, 0
total = len(test_labels)
for item in np.array(normalize_test_group).tolist():
   result = KNN.classify_knn(item, dataSet=normalize_group, labels=labels, k=3)
   result_fact = test_dict[test_labels[i]]
   result = font_dict[result]
   print(f'正在预测中,预测结果为【{result}】 实际结果为【{result_fact}】.')
   i += 1
   if result == result_fact:
       j += 1
   else:
       print('↑')
else:
   print(f'准确率为{round(j / total * 100, 2)}%')
...
正在预测中,预测结果为【华】 实际结果为【华】.
正在预测中,预测结果为【影】 实际结果为【影】.
正在预测中,预测结果为【格】 实际结果为【格】.
正在预测中,预测结果为【意】 实际结果为【意】.
正在预测中,预测结果为【比】 实际结果为【比】.
正在预测中,预测结果为【源】 实际结果为【源】.
正在预测中,预测结果为【卫】 实际结果为【卫】.
正在预测中,预测结果为【找】 实际结果为【找】.
正在预测中,预测结果为【.】 实际结果为【..
准确率为100.0%

完整项目代码在github。
https://github.com/Yakuho/KNN_Font

最后

欢迎各位和我一起交流交流技术,若你有一些更好的处理方法或者找到我的一些错误,欢迎指出,作者本人水平有限。并且如果觉得有用,请在github留下你们的stars.谢谢.

参考资料
https://baike.baidu.com/item/%E9%82%BB%E8%BF%91%E7%AE%97%E6%B3%95/1151153?
https://zhuanlan.zhihu.com/p/76636123

你可能感兴趣的:(Python机器学习,KNN,字体反爬)