woff字体反爬实战,10分钟就能学会(ttf字体同理)

woff字体反爬实战,10分钟就能学会(ttf字体同理)声明 本帖子仅是用于学习用途 请勿与用于而已破坏别人网站 本人不承担法律责任 来继续学爬虫呀 前言简单描述一下这种手段 html 源码的数字跟页面展示的数字是不一致的 当时就一脸黑人问号 嗯 经过分析 当前这种字体反爬机制是 通过获取指定链接的 woff 字体文件 然后根据 html 源码的数字去 woff 字体文件里面查找真正的数字 讲到底就是一个映射关系 查找字典 如 html 源码是 123 去 w

声明:本帖子仅是用于学习用途,请勿与用于恶意破坏别人网站,本人不承担法律责任。

前言
简单描述一下这种手段,html源码的数字跟页面展示的数字是不一致的!当时就一脸黑人问号,嗯???
经过分析,当前这种字体反爬机制是:通过获取指定链接的woff字体文件,然后根据html源码的数字
去woff字体文件里面查找真正的数字,讲到底就是一个映射关系/查找字典。如html源码是123,去woff文件里面
查找出来的是:623。好了,看到这里,你一定想说:废话讲那么多干嘛?赶紧上教程啊!!
那先来看一下大致流程呗:

woff字体反爬实战,10分钟就能学会(ttf字体同理)

tips: 一开始不知道是怎么下手,只能谷歌搜索字体反爬,一搜果然很多说法,有说woff文件的、有说CSS的、还有说svg曲线啥的, 然后我就去查看Network里面的All,就发现关键字眼woff,就开始猜测可能是属于这种类型的反爬手段,接着开始干活。 
混淆前字体:

在这里插入图片描述

混淆后的字体:

在这里插入图片描述

找了一会,发现.woff2文件和woff文件前后不一样,然后开始着手解决

如需下载woff文件,请点击这里, 提取码: ghnx

但是本地打不开woff字体文件,需要借助的软件是fontcreator,这个你自己去找一下,很多激活成功教程的

在这里插入图片描述
但是这好像看不出什么,然后我们接着需要从另外一方面下手,重点来了》将woff文件转换为xml文件
如下:




import os import requests from fontTools.ttLib import TTFont base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) url = "http://xxxxxx.xxx.woff" woff_dir = os.path.join(base_dir, "statics/woffs/") file_name = url.split("/")[-1] xml_name = file_name.replace(file_name.split(".")[-1], "xml") save_woff = os.path.join(woff_dir, file_name) save_xml = os.path.join(woff_dir, xml_name) resp = requests.get(url="xxx") with open(save_woff, "wb") as f: f.write(resp.content) f.close() font = TTFont(save_woff) font.saveXML(save_xml) # 转换为xml文件 
①的映射关系,在这里我定义为before_code_id
②的映射关系,在这里我定义为affter_code_id,结果如下:
before_code_id =  {
    "0": "cid00019",
    "1": "cid00020",
    "2": "cid00017",
    "3": "cid00021",
    "4": "cid00022",
    "5": "cid00024",
    "6": "cid00026",
    "7": "cid00025",
    "8": "cid00023",
    "9": "cid00018"
}
affter_code_id = {
    "cid00017": 2,
    "cid00018": 3,
    "cid00019": 4,
    "cid00020": 5,
    "cid00021": 6,
    "cid00022": 7,
    "cid00023": 8,
    "cid00024": 9,
    "cid00025": 10,
    "cid00026": 11
}

然后从html源码到before_code_id, affter_code_id应用起来就是如下:
前端数字—中间人code—最终的数字,即:
"0"——"cid00019"——4
"1"——"cid00020"——5
"2"——"cid00017"——2
"3"——"cid00021"——6
"4"——"cid00022"——7
"5"——"cid00024"——9
"6"——"cid00026"——11
"7"——"cid00025"——10
"8"——"cid00023"——8
"9"——"cid00018——3

我们再简化一步,直接从html源码数字到最终的数字映射为如下(即直接省去中间的cidxxxxx这串):
"0"——4
"1"——5
"2"——2
"3"——6
"4"——7
"5"——9
"6"——11
"7"——10
"8"——8
"9"——3


但是你们发现这映射后的数字很奇怪吗,比如"6"、"7"映射之后分别为11和10,
但是在我们的正常逻辑之中不对呀,要不我们再列一下html源码跟前端的肉眼看到的数字的映射关系呗:
"0"——2
"1"——3
"2"——0
"3"——4
"4"——5
"5"——7
"6"——9
"7"——8
"8"——6
"9"——1
哇,这列出来之后不是很相似吗,跟前面的结果,要不我再放在一起给你们好对比一下呗:
xml提取的映射     html源码跟网页展示的,提取的映射
"0"——4				"0"——2
"1"——5				"1"——3
"2"——2				"2"——0
"3"——6				"3"——4
"4"——7				"4"——5
"5"——9				"5"——7
"6"——11				"6"——9
"7"——10				"7"——8
"8"——8				"8"——6
"9"——3				"9"——1

到此,我们发现从xml提取的映射跟html源码跟网页展示的提取的映射数值都是相差2,所以我们大胆猜测:网页上看到的数值是可以从xml提取的映射关系里面每个数字减去2所得的,即:

"0"——4-2=2 "1"——5--2=3 "2"——2-2=0 "3"——6-2=4 "4"——7-2=5 "5"——9-2=7 "6"——11-2=9 "7"——10-2=8 "8"——8-2=6 "9"——3-2=1 

所以这就是激活成功教程了嘛,到此,这个教程总可以理解吧,写得辣么辛苦、改的辣么辛苦,赶快评论点赞收藏一套走起来

好了,别嗨了,实操才是王道,下面来看一下核心代码,如下:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019/8/19 13:08
# @Author  : qizai
# @File    : crawl_woff.py
# @Software: PyCharm

# 先安装:pip3 install fontTools
import os
import requests
from fake_useragent import UserAgent
from fontTools.ttLib import TTFont  # 对字体文件进行格式转换

base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ua = UserAgent()
header = {
    "user-agent": ua.chrome,
}


def parse_woff(url=""):
    """这里是下载字体并且解析对应的值"""
    global cookie
    global header
    
    woff_dir = os.path.join(base_dir, "statics/woffs/")
    file_name = url.split("/")[-1]
    xml_name = file_name.replace(file_name.split(".")[-1], "xml")
    save_woff = os.path.join(woff_dir, file_name)
    save_xml = os.path.join(woff_dir, xml_name)

    if os.path.exists(save_woff):  # 存在本地的话直接提取本地的文件去解析即可省去下载,避免浪费资源
        font = TTFont(save_woff)
    else:
        resp = requests.get(url=url, cookies=cookie, headers=header)
        with open(save_woff, "wb") as f:
            f.write(resp.content)
            f.close()
        font = TTFont(save_woff)
        font.saveXML(save_xml)  # 转换为xml文件

    cmap = font.getBestCmap()  # 这个是xml源码里面的【数值-中间人code】映射,数值还不一定是html源码里面的数值,而是每位数经过加上一定的数值之后的
    tmp = {  # 这个是对应的才是我们需要的值,或者你也可以在每次获取的时候,将这个值对应减去48即可,就可以省去这这个映射
        48: 0,  # html源码里面的0对应xml源码里面的48
        49: 1,  # html源码里面的1对应xml源码里面的49
        50: 2,  # html源码里面的2对应xml源码里面的50
        51: 3,  # html源码里面的3对应xml源码里面的51
        52: 4,  # html源码里面的4对应xml源码里面的52
        53: 5,  # html源码里面的5对应xml源码里面的53
        54: 6,  # html源码里面的6对应xml源码里面的54
        55: 7,  # html源码里面的7对应xml源码里面的55
        56: 8,  # html源码里面的8对应xml源码里面的56
        57: 9,  # html源码里面的9对应xml源码里面的57
    }    # 注意:个人猜测以上这个tmp字典,xml源码的数字跟html源码数字的映射关系可能会定期改变的

    before_code_id = {}  # 转换之后before_code_id为:1:cid00019  key就是html源码数字,value就是用来查询的中间人code
    for k, v in cmap.items():
        if k not in set(range(48, 58)):
            continue
        before_code_id[tmp.get(k)] = v  # 这一步其实是将49:cid00019的映射格式转换为好理解的1:cid00019映射关系

    code_id_list = font.getGlyphOrder()[2:]  # 这个返回的值有11个,但是我这里只是取了第三个到最后一个,是用来取计算前端看到的真正的数值
    affter_code_id = {k:v for k,v in zip(code_id_list, range(2, 12))}  # 将每一个按照顺序映射为cid00562:2这种

    return before_code_id, affter_code_id


if __name__ == '__main__':
    """使用如下"""
    before_code_id, affter_code_id = parse_woff(url="xxxx")
    
    # html源码数字:假设为0
    html_number = 0
    tmp_code = before_code_id.get(html_number)  # 先匹配中间人code
    real_number = affter_code_id.get(tmp_code) - 2  # 再提取中间人code对应的真正的数字,记得要减去2,因为本来是每位数字已经多了2
    print("当前html源码数字html_number:{} 真正的数字为real_number:{}".format(html_number, real_number))

当前的woff字体反爬已经激活成功教程了,如果有不妥的地方请指出,大家一起学习。

至此本文教程写完了,希望能够帮助到各位在爬虫路上的小伙伴们,觉得不错点个赞呗
感谢认真读完这篇教程的您

先别走呗,这里有可能有你需要的文章:

打赏喝咖啡
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/201769.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午8:39
下一篇 2026年3月20日 上午8:39


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号