题目:采集这5页中胜点列的数据,找出胜点最高的召唤师,将召唤师姓名填入答案中
地址:https://match.yuanrenxue.cn/match/7
本题主要是考察字体的动态变化,同样也是从字体文件下手构造出映射关系就好,但本题的映射关系相对来说要多出几个步骤。接下来至今进入分析。
可以看到响应数据中存在一个woff键值对,而它的值是base64编码过的,所以第一步我们可以先将这个woff键的值复制下来进行base64的解码然后写入字体文件之中。
from fontTools.ttLib import TTFont
woff = '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'
woff_file = base64.b64decode(woff.encode())
with open('base.woff', 'wb')as f:
f.write(woff_file)
然后写一个xml文件来查看一下其映射关系是否能够直接获取明文(这个案例中是无法直接获取的)。
很明显并没有任何对我们有用的数据,code的值转换成10进制之后也并不是明文数字。那接下来应该怎么办呢?接下来我们来观察一下响应内容和字体文件中是否存在着共同点。
结合上方xml截图和响应数据截图来看相应数据的value就是xml中看到的name值,所以我们可以根据这个关系来构造一个基本的明文数字与name之间的映射模板。
r_map = {'unia813': 3, 'unia643': 2, 'unic195': 6, 'unib671': 5, 'unic268': 0, 'unib519': 4, 'unia594': 1, 'unib713': 9,
'unia261': 8, 'unib741': 7} # 数字映射字典
这个模板可以根据页面中看到的明文内容结合响应数据来构造,也可以使用字体文件处理工具来构造
构造完之后来重新请求一下并获取字体文件,会发现每一次数字映射的name值都是不同的。如第一次请求unia813明文为3的话,下一次请求可能就变成了unia439的明文为3了。所以一直使用一个模板肯定是不行的。但是这里我们对比多次请求获取到的字体文件转换的xml文件会发现每一个数字尽管其对应的name不同,但其坐标点的位置是相同的。
同一个数字,它在坐标系中的坐标点是相同的,所以我们可以根据on数组是否相同来判断两次请求的数字是否是同一个,如果是同一个的话我们再去映射最先构造好的基本模板(基本模板中也要获取on数组用于和新请求中的on数组进行对比)。
def base_font_map():
"""构造基本on数组映射模板"""
ttobj = TTFont('base.woff')
tt_names = ttobj.getGlyphNames()[1:] # 获取所有name值
cmap = {}
for i in tt_names:
cmap[tuple(ttobj['glyf'][i].flags)] = i # 构造基本映射on数组模板
return cmap
def aim_font():
"""目标字体文件映射处理"""
res_num = {} # 最新请求的明文映射
cmap = base_font_map()
response = requests.get(url, headers=headers)
res_data = response.json()
woff = res_data['woff']
woff_file = base64.b64decode(woff.encode())
with open('aim.woff', 'wb') as f:
f.write(woff_file)
ttobj_aim = TTFont('aim.woff')
tt_names_aim = ttobj_aim.getGlyphNames()[1:]
for i in tt_names_aim:
print(tuple(ttobj_aim['glyf'][i].flags))
print('基本模板的name', cmap[tuple(ttobj_aim['glyf'][i].flags)])
print('当前请求的name', i)
res_num[i] = r_map[cmap[tuple(ttobj_aim['glyf'][i].flags)]] # 将当前请求的name对应的每一个on数组进行明文映射
print(res_num)
输出结果如下:
这样明文的关系就成功映射好了,然后就是去将5页的数据全部映射出来并求出最大值就可以了。
当然这里也可以不够早新旧模板的映射,而直接获取最新字体文件并获取到每一个数字的坐标然后根据坐标绘制出坐标图再通过识别算法来识别绘制出来的数字。
结果如下:
由于需要填入的是召唤师的姓名,所以还需要我们去映射一下每一个召唤师和其胜点的关系,召唤师名直接从网页源代码中可以获取。
最终执行结果:
验证
完整代码请移步https://gitee.com/shuailiuquan/spider-code/tree/master/