今天讲猿人学第七题
地址:
http://match.yuanrenxue.com/match/7
目录:
1、环境
2、分析请求
3、实现爬取
1、环境
Python3.7、fontTools、requests
2、分析请求
老规矩找到数据接口,看到了这些有规律的字符串,又看到了woff就知道是字体反爬了。请求完数据接口后会下载一个woff文件,就是将数据接口返回的woff请求一下,如图2-2
woff是一种字体的格式。
如图2-3的1,其实就是由图2-4的坐标连接得到的。图2-4中的unif856 把uni换成&#x就是服务器返回的数据了。
别高兴的太早了,每次请求的woff文件都是不同的。我一开始想的是woff再怎么变,表现出的字体都是不变的,这样就可以用ocr识别,但题目要求不能用ocr。那就只能找woff文件中不变的数据,坐标应该不变吧.
如图2-5两个坐标表示的都是1这个数字,坐标是变的,但意外的发现坐标后的on是不变的,那我们可以把前10个on属性挑出来组成一个数,用字典映射就好了[1]
number_woff = {
'1010010010': 0, '1001101111': 1, '1001101010': 2, '1010110010': 3, '1111111111': 4,
'1110101001': 5, '1010101010': 6, '1111111': 7, '1010101011': 8, '1001010100': 9
}
3、实现爬取
首先将返回的data去掉&#x,如:{'value': '셲 줘 셲 ꚁ '}变为c172c918c172a681,再将woff用base64解码以二进制写入文件中,之后主要就是字典的映射处理好就可以了,实在不会的可以私信我。可能大家对fontTools不熟悉,我这两天会写一篇fontTools的介绍。
全部代码
import base64
import requests
from fontTools.ttLib import TTFont
headers = {
'Host': 'match.yuanrenxue.com',
'Referer': 'http://match.yuanrenxue.com/match/6',
'User-Agent': 'yuanrenxue.project',
}
number_woff = {
'1010010010': 0, '1001101111': 1, '1001101010': 2, '1010110010': 3, '1111111111': 4,
'1110101001': 5, '1010101010': 6, '1111111': 7, '1010101011': 8, '1001010100': 9
}
def get_page(url):
return requests.get(url=url, headers=headers).json()
def decode_base64(content):
return base64.b64decode(content)
def write_woff(data, name):
with open(f'{name}.woff', 'wb') as file:
file.write(data)
def parse_woff(name):
"""获取uni...对应的数字"""
font = TTFont(f'{name}.woff')
font.saveXML(f'{name}.xml')
uni_list = font.getGlyphOrder()
uni_list.remove('.notdef')
real_number_dict = {}
for uni in uni_list:
temp = ''
for i in font['glyf'][uni].flags[:10]:
temp += str(i)
real_number = number_woff[temp]
real_number_dict[uni] = real_number
return real_number_dict
def get_original_data(url, woff_file_name):
"""获取混淆后的数字"""
confuse_numbers = []
content = get_page(url=url)
write_woff(data=decode_base64(content=content['woff']), name=woff_file_name)
for _ in content['data']:
confuse_numbers.append(_['value'].replace('&#x', '').replace(' ', ''))
return confuse_numbers
def get_real_value(value_data, original_value):
real_value_list = []
for i in original_value:
number = ''
for index in range(len(i) // 4):
index = index * 4
number += str(value_data['uni' + i[index: index + 4]])
real_value_list.append(int(number))
return real_value_list
if __name__ == '__main__':
for page in range(1, 6):
woff_file_name = 'woff_data'
url = f'http://match.yuanrenxue.com/api/match/7?page={page}'
original_value = get_original_data(url=url, woff_file_name=woff_file_name)
real_data = parse_woff(woff_file_name)
real_value = get_real_value(value_data=real_data, original_value=original_value)
print(real_value)
运行结果:
参考资料