tslilove

V1

2022/08/01阅读:12主题:山吹

字体反爬之好租

声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!


采集需求:

当然你可以再进行详情页,这里主要研究学习为主

主页:aHR0cHM6Ly94dWFuemhpLjU4LmNvbS8=

目标列表页:aHR0cHM6Ly94dWFuemhpLjU4LmNvbS9iai9ob3VzZS1saXN0Lw==

我们下面进行抓包看看,发现部分数字被加密了,呈现为一种方框的形式,有经验的小朋友一看就知道是字体反爬,对应源码中以&#x开头的字符串

我们接着看请求字体包,我们发现,该font-woff字体文件是经过Base64编码以后的字符串,我们在网页搜索一下woff,正是在网页源码中,这一步,我们可通过获取页面源码得到字体编码字符串

通过多次测试,发现字体不是静态的一套字体,将字体编码转换为woff字体

def new_save_font(page,text):
    font_encryptData = text
    binData = base64.decodebytes(font_encryptData.encode())
    with open(f'./woff/{page}.woff''wb') as f:
        f.write(binData)
        f.close()
    return f'./woff/{page}'

先通过在线网站查看(https://font.qqe2.com/),可以证实,对应数字的编码字符是不一样的,这样我们就不能固定一套字体来进行映射

当然你也可以通过fontTools.ttLib import的类方法TTFont,将woff字体保存为xml文件,方便我们查看比对

from fontTools.ttLib import TTFont
font = TTFont('./woff/1.woff')
font.saveXML('./woff/font1.xml')
font = TTFont('./woff/2.woff')
font.saveXML('./woff/font2.xml')

然后我们获取一下字体的坐标数据,绘制出字体图,这里以数字8为例

#导入matplotlib图表库
import matplotlib.pyplot as plt

#字体坐标,这里均为数字8
GlyphCoordinates1 = [(181, 371),(71, 412),(56, 521),(71, 603),(128, 656),(198, 710),(282, 710),(362, 710),(421, 647),(495, 596),(495, 507),(495, 412),(386, 371),(462, 344),(489, 300),(524, 251),(524, 184),(524, 88),(391, -39),(283, -25),(174, -39),(110, 25),(42, 86),(42, 186),(42, 257),(114, 354),(163, 509),(163, 470),(200, 439),(230, 414),(284, 406),(331, 406),(369, 439),(402, 470),(402, 567),(334, 635),(229, 635),(163, 570),(163, 524),(134, 186),(134, 146),(169, 75),(207, 55),(242, 35),(284, 21),(316, 35),(343, 46),(372, 57),(390, 77),(432, 117),(432, 248),(376, 301),(346, 332),(217, 332),(179, 290),(134, 249),(134, 198)]
GlyphCoordinates2 = [(193, 371),(71, 412),(71, 521),(71, 603),(185, 710),(378, 710),(495, 596),(495, 519),(509, 412),(386, 371),(454, 345),(524, 251),(524, 184),(524, 88),(458, 11),(391, -39),(174, -39),(108, 25),(42, 86),(42, 186),(37, 257),(78, 301),(114, 354),(181, 357),(163, 524),(163, 470),(197, 439),(223, 406),(284, 413),(333, 406),(369, 439),(402, 470),(402, 519),(398, 567),(354, 601),(334, 635),(229, 635),(197, 603),(163, 576),(148, 524),(134, 186),(134, 159),(152, 111),(169, 75),(207, 55),(242, 35),(284, 35),(316, 35),(369, 57),(390, 81),(432, 116),(432, 183),(432, 235),(389, 290),(346, 332),(281, 332),(204, 332),(179, 290),(134, 249)]
def makeFontChart(a1,a2):
    #plot1
    x1 = [i[0] for i in a1]
    y1 = [i[1] for i in a1]
    
    plt.subplot(1,2,1)
    plt.scatter(x1, y1)
    plt.plot(x1,y1)
    plt.title("font1")
    
    #plot2
    x2 = [i[0] for i in a2]
    y2 = [i[1] for i in a2]
    
    plt.subplot(1,2,2)
    plt.scatter(x2, y2)
    plt.plot(x2,y2)
    plt.title("font2")
    plt.show()
makeFontChart(GlyphCoordinates1,GlyphCoordinates2)

可见,虽然字体的坐标不同,但是确实是同一个字

那既然字体是动态的,有没有一些什么好的方案么?答案是有的,有很多博主采用坐标差值到一定阈值内,就视为同一个字,但本文采用K近邻算法进行训练,预测每个出每个字体,关于K近邻算法,网上有很多教程,这里不做过多赘述。

KNN训练算法:

def _knn():
    # 处理缺失值
    imputer = SimpleImputer(missing_values=np.nan, strategy='mean')
    data = pd.DataFrame(imputer.fit_transform(pd.DataFrame(get_font_data())))
    # 取出特征值\目标值
    x = data.drop([0], axis=1)
    y = data[0]
    # 分割数据集
    # x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
    x_train = x.head(40)
    y_train = y.head(40)
    # x_test = x.tail(10)
    # y_test = y.tail(10)
    # 标准化
    # std = StandardScaler()
    # x_train = std.fit_transform(x_train)
    # x_test = std.transform(x_test)
    # 进行算法流程
    knn = KNeighborsClassifier(n_neighbors=1)
    # 开始训练
    knn.fit(x_train, y_train)
    return knn,x.shape[1]
    # 预测结果
    # y_predict = knn.predict(x_test)
    # print(y_test,y_predict)
    # 得出准确率
    # print(knn.score(x_test, y_test))

下面就是进行实战获取环节,刷新网页

获取前两页,发现我网页的一致


总结:当遇到站点字体是动态字体时,我们就不能只考虑固定的字体编码映射,尝试 K近邻算法进行训练,预测来达到实时映射的目的!

分类:

后端

标签:

Python

作者介绍

tslilove
V1