声明:本帖子仅是用于学习用途,请勿与用于恶意破坏别人网站,本人不承担法律责任。
来继续学爬虫呀!
前言
简单描述一下这种手段,html源码的数字跟页面展示的数字是不一致的!当时就一脸黑人问号,嗯???
1 | 经过分析,当前这种字体反爬机制是:通过获取指定链接的woff字体文件,然后根据html源码的数字 |
那先来看一下大致流程呗:
分析目标网站页面(在这里我不打算贴出网站地址,请大家自己找网站练习),这里看到html源码和页面展示的数字是不一致的,如下图:
1 | tips: |
混淆前字体:
混淆后的字体:
找了一会,发现.woff2文件和woff文件前后不一样,然后开始着手解决
如需下载woff文件,请点击这里, 提取码: ghnx
但是本地打不开woff字体文件,需要借助的软件是fontcreator,这个你自己去找一下,很多破解的
但是这好像看不出什么,然后我们接着需要从另外一方面下手,重点来了》==将woff文件转换为xml文件==
如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import 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文件
然后打开xml文件看,先来查看一下缩略的内容,红色圈圈的那两个是本次重点破解的分析的内容:
然后先查看cmap,发现线索,里面注释的地方有标注了。然后我们大胆猜测:NINE对应的name=cid00018,code=0x39,这翻译过来就是9对应的name=cid00018,其id标记为0x39:
接着来看一下code=0x39,其对应的name=cid00018,然后我们拿这个cid00018去搜索,发现在<GlyphID id="3" name="cid00018"/>
,这表明什么呢?结合前后两个映射关系,然后连起来再大胆猜测一下,可能是9对应3?
为了验证这个猜想,继续再找一下其他例子,我使用已经转换为如下格式,方便你们对比,你们也可以从三张截图来对比,哪三张截图呢?分别是:①是前面包含“code=0x39,name=cid00018”的截图;②是包含“id=3,name=cid00018”的截图;③是文章的第二张截图。
你们可以①②截图来一个个列出映射关系,建议先列出①的映射关系,再列出②的映射关系,然后再将①、②的映射关系组合起来,得出一个新的映射关系,这个新的映射关系就是我们所需的,下面来给你们看一下我提取的①、②的映射关系:
1 | ①的映射关系,在这里我定义为before_code_id |
到此,我们发现从xml提取的映射跟html源码跟网页展示的提取的映射数值都是相差2,所以我们大胆猜测:网页上看到的数值是可以从xml提取的映射关系里面每个数字减去2所得的,即:
1 | "0"——4-2=2 |
所以这就是破解了嘛,到此,这个教程总可以理解吧,写得辣么辛苦、改的辣么辛苦,赶快评论点赞收藏一套走起来
好了,别嗨了,实操才是王道,下面来看一下核心代码,如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76#!/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字体反爬已经破解了,如果有不妥的地方请指出,大家一起学习。
至此本文教程写完了,希望能够帮助到各位在爬虫路上的小伙伴们,觉得不错点个赞呗
感谢认真读完这篇教程的您
先别走呗,这里有可能有你需要的文章: