Python 爬虫 | 猿人学第七题

本文介绍了如何使用Python解析包含字体反爬机制的网页,通过分析woff字体文件,利用fontTools库解析并转换为数字。首先获取数据接口返回的woff文件,然后进行base64解码并保存。接着解析woff文件,提取不变的on属性组合成数字,通过预定义的字典映射得到真实数字。最终实现了从混淆数据到真实数字的转换过程。
摘要由CSDN通过智能技术生成

今天讲猿人学第七题


地址:

match.yuanrenxue.com/ma


目录:

1、环境

2、分析请求

3、实现爬取



1、环境

Python3.7、fontTools、requests


2、分析请求

492643d9713c34fe7e3593b792730a37.jpeg
图2-1

老规矩找到数据接口,看到了这些有规律的字符串,又看到了woff就知道是字体反爬了。请求完数据接口后会下载一个woff文件,就是将数据接口返回的woff请求一下,如图2-2

c8eee94db59f226d0dc5a305623cb8e0.jpeg
图2-2

woff是一种字体的格式。

28cb16850ef0e420384d50c2c70c9972.jpeg
图2-3

0d1aeef19467505b06aace69be59c4d0.png
图2-4

如图2-3的1,其实就是由图2-4的坐标连接得到的。图2-4中的unif856 把uni换成&#x就是服务器返回的数据了。

别高兴的太早了,每次请求的woff文件都是不同的。我一开始想的是woff再怎么变,表现出的字体都是不变的,这样就可以用ocr识别,但题目要求不能用ocr。那就只能找woff文件中不变的数据,坐标应该不变吧.

1408ec7e8f6fec50c04c9c81322a415d.png
图2-5

如图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': '&#xc172 &#xc918 &#xc172 &#xa681 '}变为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)

运行结果:


c77c9638b3b80030fa20560bf44b27df.png

参考资料

[1] syjun.vip/archives/283.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值