K近邻思想解决字体反爬

猫眼电影字体反爬

1.解决思路

1.1 获取对照组字体文件,按照不同字形字体的unicode得到文字与其坐标的对应关系形成可遍历的数据结构,然后处理成可计算的数组或者直接遍历出所有的坐标数据;
1.2 再提取当前访问页面的自定义字体文件,取出其各个文字对应的坐标信息,然后也处理成数组或者遍历出所有的坐标;
1.3 将最新的坐标数据与对照字体的坐标数据进行计算,得出最小的差别值的索引值,再根据这个索引取出匹配度最高的文字;
1.4 再根据匹配到的文字对应的unicode找出html源码中加密的位置将文字替换上去。

2.网页解析

2.1 猫眼电影加密字体为数字类型的,并且每次刷新都是不同字形的字体,所以字体文件需实时获取;
在这里插入图片描述
2.2 下载字体文件后用分析工具打开对照源码查看编码对应关系,源码中代替数字的编码后四位与字体文件中数字对应的unicode的后四位相同;
在这里插入图片描述
在这里插入图片描述
2.3 字体文件还包含了了这种字体每个数字形成的坐标数据,可用fonttools模块中的TTFont打开字体文件获取;

# 打开字体文件
new_font = TTFont('./fonts/current.woff')
# 以xml格式保存,查看各种对应关系
new_font.savexml('./fonts/fong.xml')
# 可获取各个数字对应的unicode,索引对应数字的索引
unicodes = new_font.getGlyphOrder()[2:]
# 根据unicode获取对应数字的坐标信息
contour=new_font['glyf'}[unicode].coordinates
3.重要代码实现

3.1 获取5组字体数据,手动创建成对照表;

from fontTools.ttLib import TTFont

def get_font_infos():
	"""
	获取下载的各种字体信息,作为样例进行训练
	:return: 返回全部字体的坐标信息
	"""

	font1=TTFont('./fonts/1.woff')
	order1=[3,8,2,6,5,9,7,1,0,4]
	contour1=get_contour(font1,order1)

	font2=TTFont('./fonts/2.woff')
	order2=[9,4,0,7,1,5,2,8,6,3]
	contour2=get_contour(font2,order2)

	font3 = TTFont('./fonts/3.woff')
	order3 = [9,5,6,0,7,3,2,1,8,4]
	contour3= get_contour(font3, order3)

	font4 = TTFont('./fonts/4.woff')
	order4 = [6,1,3,2,5,7,0,8,9,4]
	contour4 = get_contour(font4, order4)

	font5 = TTFont('./fonts/5.woff')
	order5 = [6,1,4,0,3,7,2,9,8,5]
	contour5 = get_contour(font5, order5)
	
	contours=contour1+contour2+contour3+contour4+contour5
	return contours

def get_contour(font,order):
	"""
	获取下载好的各个字体的坐标信息
	:param font: 不同的字体文件
	:param order: 不同顺序(字体)的实例
	:return: 返回各个字体的坐标信息
	"""
	unicodes=font.getGlyphOrder()[2:]
	infos=[]
	font_dict={}
	# 用枚举函数遍历出字体的Unicode及对应的索引
	for index,unicode in enumerate(unicodes):
		contour=font['glyf'][unicode].coordinates
		contour_list=[i for items in contour for i in items]
		# 根据索引得出各个文字对应的坐标信息,并将文字添加到对应的坐标信息列表中
		contour_list.insert(0,order[index])
		infos.append(contour_list)
	# 打印出需要的对照表,新建font_data存储对照表
	print(font_dict)
	return infos

if __name__=='__main__':
	get_font_infos()

3.2 获取对照表中坐标及数字顺序的标签,转化成数组以备后续与实时获取的字体信息进行运算比较;

import numpy as np
from . import font_data

def base_array():
	"""
	根据制作好的字体对照表创建可以进行比较的数组
	:return: 创建好的训练数组及各种字体的存在形式
	"""
	# 获取对照表中存储的各种字体的数字顺序
	orders=[data[0] for data in font_data]
	# 坐标
	contour=[data[1] for data in font_data]
	# 创建50行,150个数位0的数组
	base_array=np.zeros([50,150])
	# print(base_array)
	for index,array in enumerate(contour):
		# base_array中第index+1行且1到len(array)的数据等于array的全部数据(将array替换到base_array[index,:len(array)]索引指示的位置)
		base_array[index,:len(array)]=array
	return base_array,orders

3.3 获取当前访问时的字体数据,转化成数组与对照组进行运算匹配,获取匹配度最高的数字;

def get_num(new_array,base_array,orders,k=5):
	"""
	得到自定义字体的坐标数组后与训练数组进行knn计算,得到knn系数后取出最相似的5个对应的索引,
	再根据索引得到对应的数字
	:param new_array: 新的自定字体坐标数组
	:param base_array: 训练数组
	:param orders: 不同训练字体的样式标签
	:param k: 获取的相似字体数目
	:return: 返回匹配度最高的数字
	"""
	# 根据knn公式获取knn值
	diff=(((np.tile(new_array,(50,1))-base_array)**2).sum(axis=1))**0.5
	# 将对比后的knn系数进行排序并返回其索引值
	diff_index=diff.argsort()
	count_num={}
	for i in range(k):
		# 根据diff值的索引获取相应位置的数字
		num=lables[diff_index[i]]
		# 用字典标记某个字匹配的次数,记录在value上,出现就加1,没有就为0
		count_num[num]=count_num.get(num,0)+1
	# 取出字典中某个字的匹配次数(可能有多个字)再按照字的出现频率进行排序
	count_list=sorted(count_num.items(),key=lambda x:x[1],reverse=True)
	return count_list[0][0]

def knn_main(new_contour_list):
	"""执行knn操作,获取到匹配度最高的数字"""
	base_array, orders = train_array()
	new_array = np.zeros([150])
	new_array[:len(new_contour_list)] = new_contour_list
	num=get_num(new_array,base_array,orders,5)
	return num

3.4 最后的到当前字体的unicode与数字的对应关系,再根据unicode与源码中替代数字的编码关系对其进行替换,然后进行解析数据(1-3点的代码即可完成字体反爬,这步可根据自己的要求进行定制补充)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值